Skip to content

Commit

Permalink
Merge pull request #1272 from Jaseci-Labs/thakee-trailing-comma
Browse files Browse the repository at this point in the history
trailing comma support implemented
  • Loading branch information
marsninja authored Oct 2, 2024
2 parents c9c0b30 + 69d5d32 commit 93cae23
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 73 deletions.
28 changes: 14 additions & 14 deletions jac/jaclang/compiler/jac.lark
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ from_path: (DOT | ELLIPSIS)* import_path
| (DOT | ELLIPSIS)+

import_path: named_ref (DOT named_ref)* (KW_AS NAME)?
import_items: (import_item COMMA)* import_item
import_items: (import_item COMMA)* import_item COMMA?
import_item: named_ref (KW_AS NAME)?
sub_name: COLON NAME
include_stmt: KW_INCLUDE sub_name? import_path SEMI
Expand Down Expand Up @@ -63,7 +63,7 @@ enum: decorators? enum_decl

enum_decl: KW_ENUM access_tag? STRING? NAME inherited_archs? (enum_block | SEMI)
enum_def: arch_to_enum_chain enum_block
enum_block: LBRACE ((enum_stmt COMMA)* enum_stmt)? RBRACE
enum_block: LBRACE ((enum_stmt COMMA)* enum_stmt COMMA?)? RBRACE

enum_stmt: NAME (COLON STRING)? EQ expression
| NAME (COLON STRING)?
Expand All @@ -83,7 +83,7 @@ abstract_ability: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? STRING? named_ref (
genai_ability: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? STRING? named_ref (func_decl) KW_BY atomic_call SEMI
event_clause: KW_WITH expression? (KW_EXIT | KW_ENTRY) (STRING? RETURN_HINT expression)?
func_decl: (LPAREN func_decl_params? RPAREN)? (RETURN_HINT (STRING COLON)? expression)?
func_decl_params: (param_var COMMA)* param_var
func_decl_params: (param_var COMMA)* param_var COMMA?
param_var: (STAR_POW | STAR_MUL)? NAME (COLON STRING)? type_tag (EQ expression)?

// Global variables
Expand Down Expand Up @@ -364,9 +364,9 @@ index_slice: LSQUARE expression? COLON expression? (COLON expression?)? RSQUARE
// Function calls
atomic_call: atomic_chain LPAREN param_list? (KW_BY atomic_call)? RPAREN

param_list: expr_list COMMA kw_expr_list
| kw_expr_list
| expr_list
param_list: expr_list COMMA kw_expr_list COMMA?
| kw_expr_list COMMA?
| expr_list COMMA?

// Atom
atom: named_ref
Expand Down Expand Up @@ -412,20 +412,20 @@ set_compr: LBRACE expression inner_compr+ RBRACE
dict_compr: LBRACE kv_pair inner_compr+ RBRACE
inner_compr: KW_ASYNC? KW_FOR atomic_chain KW_IN pipe_call (KW_IF walrus_assign)*

dict_val: LBRACE ((kv_pair COMMA)* kv_pair)? RBRACE
list_val: LSQUARE expr_list? RSQUARE
dict_val: LBRACE ((kv_pair COMMA)* kv_pair COMMA?)? RBRACE
list_val: LSQUARE (expr_list COMMA?)? RSQUARE
tuple_val: LPAREN tuple_list? RPAREN
set_val: LBRACE expr_list RBRACE
set_val: LBRACE expr_list COMMA? RBRACE

kv_pair: expression COLON expression | STAR_POW expression
expr_list: (expr_list COMMA)? expression

// Tuples and Jac Tuples
tuple_list: expression COMMA expr_list COMMA kw_expr_list
| expression COMMA kw_expr_list
| expression COMMA expr_list
tuple_list: expression COMMA expr_list COMMA kw_expr_list COMMA?
| expression COMMA kw_expr_list COMMA?
| expression COMMA expr_list COMMA?
| expression COMMA
| kw_expr_list
| kw_expr_list COMMA?

kw_expr_list: (kw_expr_list COMMA)? kw_expr
kw_expr: named_ref EQ expression | STAR_POW expression
Expand Down Expand Up @@ -662,4 +662,4 @@ FSTR_BESC.1: /{{|}}/
COMMENT: /#\*(.|\n|\r)*?\*#|#.*/
WS.-2: /[ \t\f\r\n]/+
%ignore COMMENT
%ignore WS
%ignore WS
128 changes: 70 additions & 58 deletions jac/jaclang/compiler/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ def import_items(
) -> ast.SubNodeList[ast.ModuleItem]:
"""Grammar rule.
import_items: (import_item COMMA)* import_item
import_items: (import_item COMMA)* import_item COMMA?
"""
ret = ast.SubNodeList[ast.ModuleItem](
items=[i for i in kid if isinstance(i, ast.ModuleItem)],
Expand Down Expand Up @@ -693,7 +693,7 @@ def enum_block(
) -> ast.SubNodeList[ast.EnumBlockStmt]:
"""Grammar rule.
enum_block: LBRACE ((enum_stmt COMMA)* enum_stmt)? RBRACE
enum_block: LBRACE ((enum_stmt COMMA)* enum_stmt COMMA?)? RBRACE
"""
ret = ast.SubNodeList[ast.EnumBlockStmt](items=[], delim=Tok.COMMA, kid=kid)
ret.items = [i for i in kid if isinstance(i, ast.EnumBlockStmt)]
Expand Down Expand Up @@ -1022,7 +1022,7 @@ def func_decl_params(
) -> ast.SubNodeList[ast.ParamVar]:
"""Grammar rule.
func_decl_params: (param_var COMMA)* param_var
func_decl_params: (param_var COMMA)* param_var COMMA?
"""
ret = ast.SubNodeList[ast.ParamVar](
items=[i for i in kid if isinstance(i, ast.ParamVar)],
Expand Down Expand Up @@ -1267,29 +1267,30 @@ def code_block(
def statement(self, kid: list[ast.AstNode]) -> ast.CodeBlockStmt:
"""Grammar rule.
statement: py_code_block
| walker_stmt
| return_stmt SEMI
| report_stmt SEMI
| delete_stmt SEMI
| ctrl_stmt SEMI
| assert_stmt SEMI
| raise_stmt SEMI
| with_stmt
statement: import_stmt
| ability
| architype
| if_stmt
| while_stmt
| for_stmt
| try_stmt
| if_stmt
| expression SEMI
| (yield_expr | KW_YIELD) SEMI
| static_assignment
| assignment SEMI
| match_stmt
| with_stmt
| global_ref SEMI
| nonlocal_ref SEMI
| typed_ctx_block
| ability
| architype
| import_stmt
| return_stmt SEMI
| (yield_expr | KW_YIELD) SEMI
| raise_stmt SEMI
| assert_stmt SEMI
| check_stmt SEMI
| assignment SEMI
| delete_stmt SEMI
| report_stmt SEMI
| expression SEMI
| ctrl_stmt SEMI
| py_code_block
| walker_stmt
| SEMI
"""
if isinstance(kid[0], ast.CodeBlockStmt) and len(kid) < 2:
Expand Down Expand Up @@ -2180,30 +2181,21 @@ def cmp_op(self, kid: list[ast.AstNode]) -> ast.Token:
def arithmetic(self, kid: list[ast.AstNode]) -> ast.Expr:
"""Grammar rule.
arithmetic: term MINUS arithmetic
| term PLUS arithmetic
| term
arithmetic: (arithmetic (MINUS | PLUS))? term
"""
return self.binary_expr_unwind(kid)

def term(self, kid: list[ast.AstNode]) -> ast.Expr:
"""Grammar rule.
term: factor MOD term
| factor DIV term
| factor FLOOR_DIV term
| factor STAR_MUL term
| factor
term: (term (MOD | DIV | FLOOR_DIV | STAR_MUL | DECOR_OP))? power
"""
return self.binary_expr_unwind(kid)

def factor(self, kid: list[ast.AstNode]) -> ast.Expr:
"""Grammar rule.
factor: power
| BW_NOT factor
| MINUS factor
| PLUS factor
factor: (BW_NOT | MINUS | PLUS) factor | connect
"""
if len(kid) == 2:
if isinstance(kid[0], ast.Token) and isinstance(kid[1], ast.Expr):
Expand All @@ -2221,8 +2213,7 @@ def factor(self, kid: list[ast.AstNode]) -> ast.Expr:
def power(self, kid: list[ast.AstNode]) -> ast.Expr:
"""Grammar rule.
power: connect STAR_POW power
| connect
power: (power STAR_POW)? factor
"""
return self.binary_expr_unwind(kid)

Expand Down Expand Up @@ -2513,8 +2504,7 @@ def atom(self, kid: list[ast.AstNode]) -> ast.Expr:
def yield_expr(self, kid: list[ast.AstNode]) -> ast.YieldExpr:
"""Grammar rule.
yield_expr:
| KW_YIELD KW_FROM? expression
yield_expr: KW_YIELD KW_FROM? expression
"""
if isinstance(kid[-1], ast.Expr):
return self.nu(
Expand Down Expand Up @@ -2565,7 +2555,7 @@ def atom_collection(self, kid: list[ast.AstNode]) -> ast.AtomExpr:
def multistring(self, kid: list[ast.AstNode]) -> ast.AtomExpr:
"""Grammar rule.
multistring: (fstring | STRING)+
multistring: (fstring | STRING | DOC_STRING)+
"""
valid_strs = [i for i in kid if isinstance(i, (ast.String, ast.FString))]
if len(valid_strs) == len(kid):
Expand All @@ -2582,6 +2572,7 @@ def fstring(self, kid: list[ast.AstNode]) -> ast.FString:
"""Grammar rule.
fstring: FSTR_START fstr_parts FSTR_END
| FSTR_SQ_START fstr_sq_parts FSTR_SQ_END
"""
if len(kid) == 2:
return self.nu(
Expand All @@ -2605,7 +2596,7 @@ def fstr_parts(
) -> ast.SubNodeList[ast.String | ast.ExprStmt]:
"""Grammar rule.
fstr_parts: (FSTR_PIECE | FSTR_BESC | LBRACE expression RBRACE | fstring)*
fstr_parts: (FSTR_PIECE | FSTR_BESC | LBRACE expression RBRACE )*
"""
valid_parts: list[ast.String | ast.ExprStmt] = [
(
Expand Down Expand Up @@ -2651,7 +2642,7 @@ def fstr_sq_parts(
def list_val(self, kid: list[ast.AstNode]) -> ast.ListVal:
"""Grammar rule.
list_val: LSQUARE expr_list? RSQUARE
list_val: LSQUARE (expr_list COMMA?)? RSQUARE
"""
if len(kid) == 2:
return self.nu(
Expand Down Expand Up @@ -2695,7 +2686,7 @@ def tuple_val(self, kid: list[ast.AstNode]) -> ast.TupleVal:
def set_val(self, kid: list[ast.AstNode]) -> ast.SetVal:
"""Grammar rule.
set_val: LBRACE expr_list RBRACE
set_val: LBRACE expr_list COMMA? RBRACE
"""
if len(kid) == 2:
return self.nu(
Expand Down Expand Up @@ -2822,25 +2813,37 @@ def tuple_list(
) -> ast.SubNodeList[ast.Expr | ast.KWPair]:
"""Grammar rule.
tuple_list: expression COMMA expr_list COMMA kw_expr_list
| expression COMMA kw_expr_list
| expression COMMA expr_list
| expression COMMA
| kw_expr_list
tuple_list: expression COMMA expr_list COMMA kw_expr_list COMMA?
| expression COMMA kw_expr_list COMMA?
| expression COMMA expr_list COMMA?
| expression COMMA
| kw_expr_list COMMA?
"""
chomp = [*kid]
first_expr = None
if isinstance(chomp[0], ast.SubNodeList):
# The chomp will be like this:
# kw_expr_list, [COMMA]
if len(chomp) > 1:
# Add the comma to the subnode list if it exists, otherwise the last comma will not be a part of
# the ast, we need it for formatting.
chomp[0].kid.append(chomp[1])
return self.nu(chomp[0])
else:
first_expr = chomp[0]
chomp = chomp[2:]
# The chomp will be like this:
# expression, COMMA, [subnode_list, [COMMA, [kw_expr_list, [COMMA]]]]
# Pop the first expression from chomp.
first_expr = chomp[0] # Get the first expression.
chomp = chomp[2:] # Get rid of expr and comma.

# The chomp will be like this:
# [subnode_list, [COMMA, [kw_expr_list, [COMMA]]]]
expr_list = []
if len(chomp):
expr_list = chomp[0].kid
chomp = chomp[1:]
expr_list = chomp[0].kid # Get the kids subnode list.
chomp = chomp[2:] # Get rid of the subnode list and a comma if exists.
if len(chomp):
chomp = chomp[1:]
# The chomp will be like this: [kw_expr_list, [COMMA]]
expr_list = [*expr_list, *chomp[0].kid]
expr_list = [first_expr, *expr_list]
valid_kid = [i for i in expr_list if isinstance(i, (ast.Expr, ast.KWPair))]
Expand All @@ -2855,7 +2858,7 @@ def tuple_list(
def dict_val(self, kid: list[ast.AstNode]) -> ast.DictVal:
"""Grammar rule.
dict_val: LBRACE ((kv_pair COMMA)* kv_pair)? RBRACE
dict_val: LBRACE ((kv_pair COMMA)* kv_pair COMMA?)? RBRACE
"""
ret = ast.DictVal(
kv_pairs=[],
Expand Down Expand Up @@ -2912,7 +2915,7 @@ def list_compr(self, kid: list[ast.AstNode]) -> ast.ListCompr:
def gen_compr(self, kid: list[ast.AstNode]) -> ast.GenCompr:
"""Grammar rule.
gen_compr: LSQUARE expression inner_compr+ RSQUARE
gen_compr: LPAREN expression inner_compr+ RPAREN
"""
comprs = [i for i in kid if isinstance(i, ast.InnerCompr)]
if isinstance(kid[1], ast.Expr):
Expand All @@ -2929,7 +2932,7 @@ def gen_compr(self, kid: list[ast.AstNode]) -> ast.GenCompr:
def set_compr(self, kid: list[ast.AstNode]) -> ast.SetCompr:
"""Grammar rule.
set_compr: LSQUARE expression inner_compr+ RSQUARE
set_compr: LBRACE expression inner_compr+ RBRACE
"""
comprs = [i for i in kid if isinstance(i, ast.InnerCompr)]
if isinstance(kid[1], ast.Expr) and isinstance(kid[2], ast.InnerCompr):
Expand Down Expand Up @@ -2993,12 +2996,21 @@ def param_list(
) -> ast.SubNodeList[ast.Expr | ast.KWPair]:
"""Grammar rule.
param_list: expr_list COMMA kw_expr_list
| kw_expr_list
| expr_list
param_list: expr_list COMMA kw_expr_list COMMA?
| kw_expr_list COMMA?
| expr_list COMMA?
"""
if len(kid) == 1:
ends_with_comma = (
len(kid) > 1
and isinstance(kid[-1], ast.Token)
and kid[-1].name == "COMMA"
)
if len(kid) == 1 or (len(kid) == 2 and ends_with_comma):
if isinstance(kid[0], ast.SubNodeList):
if (
ends_with_comma
): # Append the trailing comma to the subnode list.
kid[0].kid.append(kid[1])
return self.nu(kid[0])
else:
raise self.ice()
Expand Down Expand Up @@ -3146,7 +3158,7 @@ def object_ref(self, kid: list[ast.AstNode]) -> ast.ArchRef:
def type_ref(self, kid: list[ast.AstNode]) -> ast.ArchRef:
"""Grammar rule.
type_ref: TYPE_OP name_ref
type_ref: TYPE_OP (named_ref | builtin_type)
"""
if isinstance(kid[0], ast.Token) and isinstance(kid[1], ast.NameAtom):
return self.nu(
Expand Down
4 changes: 3 additions & 1 deletion jac/jaclang/compiler/passes/tool/jac_formatter_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,9 @@ def exit_func_call(self, node: ast.FuncCall) -> None:
indented = True
for count, j in enumerate(i.kid):
if j.gen.jac == ",":
if i.kid[count + 1].gen.jac.startswith("#"):
if len(i.kid) > count + 1 and i.kid[
count + 1
].gen.jac.startswith("#"):
self.indent_level -= 1
self.emit(node, f"{j.gen.jac} ")
self.indent_level += 1
Expand Down
Loading

0 comments on commit 93cae23

Please sign in to comment.