diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 37d9d12..989c0ec 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -13,7 +13,8 @@ // ## INPUTS // #################################### -file = _{ soi ~ def_module* ~ eoi } +file = _{ soi ~ newline* ~ (file_contents ~ newline*)? ~ eoi } +file_contents = _{ def_module ~ (newline+ ~ def_module)* } // #################################### @@ -32,8 +33,8 @@ expression_infix = !{ literal ~ (binary_operator ~ literal)+ } array = !{ "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" } atom = ${ ":" ~ identifier } boolean = { boolean_true | boolean_false } -boolean_false = { "false" } -boolean_true = { "true" } +boolean_false = @{ keyword_false } +boolean_true = @{ keyword_true } braced = !{ "(" ~ expression ~ ")" } constructor = !{ type_name ~ "{" ~ argument_list? ~ "}" } literal = !{ unary | constructor | array | float | integer | string | atom | property | variable | braced | boolean | type_name } @@ -46,23 +47,38 @@ variable = @{ identifier } // ## WHITESPACE // #################################### -whitespace = _{ space | newline } -space = _{ " " | "\t" } +whitespace = _{ " " | "\t" } newline = _{ "\n" | "\r\n" } -padded_newline = _{ space* ~ newline ~ space* } -comment = _{ "#" ~ (!newline ~ any)* } +comment = _{ "#" ~ (!newline ~ any)* ~ (newline | eoi) } // #################################### // ## IDENTIFIERS // #################################### +keyword = _{ + keyword_stabby | keyword_end | keyword_def_static | + keyword_def_public | keyword_def_private | + keyword_def_type | keyword_def_trait | + keyword_def_impl | + keyword_true | keyword_false + } +keyword_stabby = _{ "->" } +keyword_end = _{ "end" ~ !identifier_tail } +keyword_def_static = { "defstatic" } +keyword_def_public = { "def" } +keyword_def_private = { "defp" } +keyword_def_type = { "deftype" } +keyword_def_trait = { "deftrait" } +keyword_def_impl = { "defimpl" } +keyword_true = { "true" } +keyword_false = { "false" } + identifier_test = _{ soi ~ identifier ~ eoi } -identifier = @{ !identifier_reserved ~ identifier_head ~ identifier_tail? } -identifier_reserved = _{ block_end | def_keyword | boolean } +identifier = @{ !keyword ~ identifier_head ~ identifier_tail? } identifier_head = @{ 'a'..'z' | "_" } identifier_tail = @{ ('a'..'z' | 'A'..'Z' | "_" | '0'..'9')+ } -type_name = @{ !identifier_reserved ~ type_name_head ~ identifier_tail? } +type_name = @{ !keyword ~ type_name_head ~ identifier_tail? } type_name_head = @{ 'A'..'Z' } @@ -71,11 +87,9 @@ type_name_head = @{ 'A'..'Z' } // #################################### block_test = _{ soi ~ block ~ eoi } -block = @{ block_stabby ~ whitespace+ ~ (block_end | block_body) } -block_stabby = _{ "->" } -block_body = _{ block_expression ~ (padded_newline+ ~ block_expression)* ~ whitespace* ~ block_end } +block = { keyword_stabby ~ newline* ~ (block_body ~ newline*)? ~ keyword_end } +block_body = _{ block_expression ~ (newline+ ~ block_expression)* } block_expression = _{ def_function | expression } -block_end = _{ "end" ~ !identifier_tail } // #################################### @@ -133,12 +147,12 @@ argument_keyword = ${ identifier ~ ":" } def_fn_keyword = _{ def_static | def_private | def_public } def_type_keyword = _{ def_trait | def_type | def_impl } def_keyword = _{ def_type_keyword | def_fn_keyword } -def_static = { "defstatic" } -def_private = { "defp" } -def_public = { "def" } -def_trait = { "deftrait" } -def_type = { "deftype" } -def_impl = { "defimpl" } +def_static = @{ keyword_def_static } +def_private = @{ keyword_def_private } +def_public = @{ keyword_def_public } +def_trait = @{ keyword_def_trait } +def_type = @{ keyword_def_type } +def_impl = @{ keyword_def_impl } def_name = ${ identifier ~ def_predicate? } def_predicate = { "?" } def_return_type = { "<" ~ type_name ~ ">" } diff --git a/parser/src/grammar/test/block.rs b/parser/src/grammar/test/block.rs index 3e750b9..07c5eb2 100644 --- a/parser/src/grammar/test/block.rs +++ b/parser/src/grammar/test/block.rs @@ -7,7 +7,7 @@ fn empty() { input: "-> end ", rule: Rule::block, tokens: [ - block(0, 6, []) + block(0, 7) ] ) } @@ -101,6 +101,23 @@ fn with_multi_function_def() { def none? end"#, rule: Rule::block_test, - tokens: [] + tokens: [ + block(0, 84, [ + def_function(23, 32, [ + def_public(23, 26), + def_name(27, 32, [ + identifier(27, 31), + def_predicate(31, 32) + ]) + ]), + def_function(53, 62, [ + def_public(53, 56), + def_name(57, 62, [ + identifier(57, 61), + def_predicate(61, 62) + ]) + ]) + ]) + ] ) } diff --git a/parser/src/grammar/test/comment.rs b/parser/src/grammar/test/comment.rs index 8ea898c..8b95351 100644 --- a/parser/src/grammar/test/comment.rs +++ b/parser/src/grammar/test/comment.rs @@ -22,8 +22,15 @@ fn leading_comment() { parser: Grammar, input: "# test 123", - rule: Rule::expression, + rule: Rule::expression_test, tokens: [ + expression(23, 26, [ + literal(23, 26, [ + integer(23, 26, [ + integer_decimal(23, 26) + ]) + ]) + ]) ] ) } diff --git a/parser/src/grammar/test/file.rs b/parser/src/grammar/test/file.rs index 709b34b..b705f74 100644 --- a/parser/src/grammar/test/file.rs +++ b/parser/src/grammar/test/file.rs @@ -11,7 +11,7 @@ fn multi_def_with_args() { ", rule: Rule::file, tokens: [ - def_module(17, 66, [ + def_module(17, 48, [ def_type(17, 24), type_name(25, 33), argument_pair(34, 48, [ @@ -23,7 +23,7 @@ fn multi_def_with_args() { ]) ]) ]), - def_module(66, 115, [ + def_module(66, 99, [ def_impl(66, 73), type_name(74, 85), argument_pair(86, 99, [ @@ -50,11 +50,11 @@ fn multi_def_no_args() { ", rule: Rule::file, tokens: [ - def_module(17, 51, [ + def_module(17, 33, [ def_type(17, 24), type_name(25, 33), ]), - def_module(51, 86, [ + def_module(51, 70, [ def_impl(51, 58), type_name(59, 70) ])