Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arithmetic expression parsing #120

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CST.ml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ and word_cst = word_component list
and word_component =
| WordSubshell of subshell_kind * program located
| WordName of string
| WordArith of word
| WordAssignmentWord of assignment_word
| WordDoubleQuoted of word
| WordSingleQuoted of word
Expand Down
17 changes: 12 additions & 5 deletions src/prelexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ rule token current = parse
If the current character is an unquoted '$' or '`', the shell shall
identify the start of any candidates for parameter expansion
(Parameter Expansion), command substitution (Command Substitution),
or ] arithmetic expansion (Arithmetic Expansion) from their
or arithmetic expansion (Arithmetic Expansion) from their
introductory unquoted character sequences: '$' or "${", "$(" or
'`', and "$((", respectively. The shell shall read sufficient input
to determine the end of the unit to be expanded (as explained in
Expand Down Expand Up @@ -432,10 +432,11 @@ rule token current = parse
}

| "$((" {
let current = push_string current "$((" in
debug ~rule:"arithmetic-exp" lexbuf current;
let current = push_arith current in
let current = next_double_rparen 1 current lexbuf in
token current lexbuf
}
}

(*specification:

Expand Down Expand Up @@ -715,16 +716,22 @@ and next_double_rparen dplevel current = parse
let current = push_string current "((" in
next_double_rparen (dplevel+1) current lexbuf
}
| "$((" {
debug ~rule:"arithmetic-exp" lexbuf current;
let current = push_arith current in
let current = next_double_rparen (dplevel+1) current lexbuf in
current
}
| '`' as op | "$" ( '(' as op) {
let escaping_level = 0 in (* FIXME: Probably wrong. *)
let current = push_string current (Lexing.lexeme lexbuf) in
let current = push_separated_string current (Lexing.lexeme lexbuf) in
let current = subshell op escaping_level current lexbuf in
let expected_closing_char = if op = '`' then '`' else ')' in
let current = close_subshell expected_closing_char current lexbuf in
next_double_rparen dplevel current lexbuf
}
| "))" {
let current = push_string current "))" in
let current = pop_arith current in
if dplevel = 1
then current
else if dplevel > 1 then next_double_rparen (dplevel-1) current lexbuf
Expand Down
31 changes: 30 additions & 1 deletion src/prelexerState.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type atom =
| WordComponent of (string * word_component)
| QuotingMark of quote_kind
| AssignmentMark
| ArithMark

and quote_kind = SingleQuote | DoubleQuote | OpeningBrace

Expand Down Expand Up @@ -216,6 +217,7 @@ let string_of_atom = function
| WordComponent (s, _) -> s
| AssignmentMark -> "|=|"
| QuotingMark _ -> "|Q|"
| ArithMark -> "|A|"

let contents_of_atom_list atoms =
String.concat "" (List.rev_map string_of_atom atoms)
Expand All @@ -238,6 +240,32 @@ let components_of_atom_list atoms =
let components b =
components_of_atom_list (buffer b)

let push_arith b =
let cst = ArithMark in
let buffer = AtomBuffer.make (cst :: buffer b) in
{ b with buffer }

let pop_arith b =
let rec aux str_expression expression = function
| [] ->
(str_expression, expression, [])
| ArithMark :: buffer -> (str_expression, expression, buffer)
| (AssignmentMark | QuotingMark _ ) :: buffer ->
aux str_expression expression buffer (* FIXME: Check twice. *)
| WordComponent (w, WordEmpty) :: buffer ->
aux (w ^ str_expression) expression buffer
| WordComponent (w, c) :: buffer ->
aux (w ^ str_expression) (c :: expression) buffer
in
let str_expression, expression, buffer = aux "" [] (buffer b) in
let word = Word (str_expression, expression) in
let expression = WordArith word in
let str_expression = "$((" ^ str_expression ^ "))"
in
let expression = WordComponent (str_expression, expression) in
let buffer = AtomBuffer.make (expression :: buffer) in
{ b with buffer }

let push_quoting_mark k b =
let cst = QuotingMark k in
let buffer = AtomBuffer.make (cst :: buffer b) in
Expand All @@ -249,7 +277,7 @@ let pop_quotation k b =
(squote, quote, [])
| QuotingMark k' :: buffer when k = k' ->
(squote, quote, buffer)
| (AssignmentMark | QuotingMark _) :: buffer ->
| (AssignmentMark | QuotingMark _ | ArithMark) :: buffer ->
aux squote quote buffer (* FIXME: Check twice. *)
| WordComponent (w, WordEmpty) :: buffer ->
aux (w ^ squote) quote buffer
Expand Down Expand Up @@ -404,6 +432,7 @@ let return ?(with_newline=false) lexbuf (current : prelexer_state) tokens =
| WordComponent (_, s) -> [s]
| AssignmentMark -> []
| QuotingMark _ -> []
| ArithMark -> []
) (buffer current)))
in
let csts = TildePrefix.recognize csts in
Expand Down
9 changes: 8 additions & 1 deletion tests/good/2.2-quoting/quoting-equal-sign.sh.expected
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,14 @@
[
"Word",
"a$((=))b",
[ [ "WordLiteral", "a$((=))b" ] ]
[
[ "WordLiteral", "a" ],
[
"WordArith",
[ "Word", "=", [ [ "WordLiteral", "=" ] ] ]
],
[ "WordLiteral", "b" ]
]
]
]
]
Expand Down
3 changes: 3 additions & 0 deletions tests/good/2.3-token-recognition/arith_exp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
echo $((1 * $((2*3)) * 42))

echo $((x+=`echo 2`))
166 changes: 166 additions & 0 deletions tests/good/2.3-token-recognition/arith_exp.sh.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
[
"Program_LineBreak_CompleteCommands_LineBreak",
[ "LineBreak_Empty" ],
[
"CompleteCommands_CompleteCommands_NewlineList_CompleteCommand",
[
"CompleteCommands_CompleteCommand",
[
"CompleteCommand_CList",
[
"CList_AndOr",
[
"AndOr_Pipeline",
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName_CmdSuffix",
[
"CmdName_Word",
[ "Word", "echo", [ [ "WordName", "echo" ] ] ]
],
[
"CmdSuffix_Word",
[
"Word",
"$((1 * $((2*3)) * 42))",
[
[
"WordArith",
[
"Word",
"1 * $((2*3)) * 42",
[
[ "WordLiteral", "1 * " ],
[
"WordArith",
[
"Word",
"2*3",
[ [ "WordLiteral", "2*3" ] ]
]
],
[ "WordLiteral", " * 42" ]
]
]
]
]
]
]
]
]
]
]
]
]
]
],
[ "NewLineList_NewLine" ],
[
"CompleteCommand_CList",
[
"CList_AndOr",
[
"AndOr_Pipeline",
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName_CmdSuffix",
[
"CmdName_Word",
[ "Word", "echo", [ [ "WordName", "echo" ] ] ]
],
[
"CmdSuffix_Word",
[
"Word",
"$((x+=`echo 2`))",
[
[
"WordArith",
[
"Word",
"x+=`echo 2`",
[
[ "WordLiteral", "x+=" ],
[
"WordSubshell",
[ "SubShellKindBackQuote" ],
[
"Program_LineBreak_CompleteCommands_LineBreak",
[ "LineBreak_Empty" ],
[
"CompleteCommands_CompleteCommand",
[
"CompleteCommand_CList",
[
"CList_AndOr",
[
"AndOr_Pipeline",
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName_CmdSuffix",
[
"CmdName_Word",
[
"Word",
"echo",
[
[
"WordName", "echo"
]
]
]
],
[
"CmdSuffix_Word",
[
"Word",
"2",
[
[
"WordLiteral", "2"
]
]
]
]
]
]
]
]
]
]
]
],
[ "LineBreak_Empty" ]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
],
[ "LineBreak_Empty" ]
]
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,16 @@
[
"Word",
"$((3 + 1))",
[ [ "WordLiteral", "$((3 + 1))" ] ]
[
[
"WordArith",
[
"Word",
"3 + 1",
[ [ "WordLiteral", "3 + 1" ] ]
]
]
]
]
]
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,16 @@
[
"Word",
"$((3 + 1))",
[ [ "WordLiteral", "$((3 + 1))" ] ]
[
[
"WordArith",
[
"Word",
"3 + 1",
[ [ "WordLiteral", "3 + 1" ] ]
]
]
]
]
]
]
Expand Down