aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChimrod <>2026-09-14 10:29:40 +0200
committerChimrod <>2026-09-14 10:29:40 +0200
commit6dd1beecbac4d1e9d3a13f3e06563659724caf10 (patch)
treef88b30e7c7a9dda9f5f0394fba5ba562d4c29b2a
parentf805783c2fe7f4dd3f970d48ae122df4dd79da23 (diff)
Managed the parens in functions without argumentsHEADmaster
-rw-r--r--lib/qparser/analyzer.ml3
-rw-r--r--lib/qparser/dune42
-rw-r--r--lib/qparser/expression_parser.messages4
-rw-r--r--lib/qparser/idents.ml2
-rw-r--r--lib/qparser/parser.mly2
-rw-r--r--lib/qparser/qsp_expression.mly140
-rw-r--r--test/syntax.ml22
-rw-r--r--test/syntax_error.ml6
8 files changed, 125 insertions, 96 deletions
diff --git a/lib/qparser/analyzer.ml b/lib/qparser/analyzer.ml
index fc0ed6d..0337baf 100644
--- a/lib/qparser/analyzer.ml
+++ b/lib/qparser/analyzer.ml
@@ -26,7 +26,8 @@ let rec parse : type a context.
and type context = context) ->
let module Parser = Parser.Make (S) in
let module IncrementalParser =
- Interpreter.Interpreter (Parser.MenhirInterpreter) in
+ Interpreter.Interpreter (Parser.MenhirInterpreter)
+ in
fun lexer_type l context ->
let get_parser :
lexer ->
diff --git a/lib/qparser/dune b/lib/qparser/dune
index eea3815..7edba9c 100644
--- a/lib/qparser/dune
+++ b/lib/qparser/dune
@@ -1,30 +1,28 @@
(library
(name qparser)
- (libraries
- str
- menhirLib
- qsp_syntax
- sedlex
- )
- (preprocess (pps
- sedlex.ppx
- ))
- )
-
+ (libraries str menhirLib qsp_syntax sedlex)
+ (preprocess
+ (pps sedlex.ppx)))
(rule
(targets parser_messages.ml)
- (deps expression_parser.messages tokens.mly qsp_expression.mly qsp_instruction.mly qsp_single_line.mly parser.mly)
- (action (with-stdout-to %{targets} (run menhir --base parser.mly --compile-errors %{deps}))))
+ (deps
+ expression_parser.messages
+ tokens.mly
+ qsp_expression.mly
+ qsp_instruction.mly
+ qsp_single_line.mly
+ parser.mly)
+ (action
+ (with-stdout-to
+ %{targets}
+ (run menhir --base parser.mly --compile-errors %{deps}))))
(menhir
- (modules tokens)
- (flags --only-tokens)
-)
-
+ (modules tokens)
+ (flags --only-tokens))
-(menhir
- (modules tokens parser qsp_instruction qsp_expression qsp_single_line)
- (flags --table --external-tokens Tokens)
- (merge_into parser)
-)
+(menhir
+ (modules tokens parser qsp_instruction qsp_expression qsp_single_line)
+ (flags --table --external-tokens Tokens)
+ (merge_into parser))
diff --git a/lib/qparser/expression_parser.messages b/lib/qparser/expression_parser.messages
index 22ffd7d..8040f05 100644
--- a/lib/qparser/expression_parser.messages
+++ b/lib/qparser/expression_parser.messages
@@ -65,7 +65,6 @@ main: LOCATION_START EOL IF IDENT COLUMN EOL ELSE STAR
main: LOCATION_START EOL IDENT DECR INTEGER SET
main: LOCATION_START EOL SET IDENT DECR INTEGER SET
main: LOCATION_START EOL LET IDENT DECR INTEGER SET
-main: LOCATION_START EOL KEYWORD INTEGER TEXT_MARKER
main: LOCATION_START EOL KEYWORD IDENT COMA INTEGER TEXT_MARKER
Missing separator between instructions
@@ -114,9 +113,10 @@ main: LOCATION_START EOL IDENT MINUS STAR
dynamics: IDENT R_PAREN
dynamics: TEXT_MARKER ENTER_EMBED FUNCTION_NOARGS TEXT_MARKER
+dynamics: TEXT_MARKER ENTER_EMBED INTEGER TEXT_MARKER
Unbalanced paren
-dynamics: IDENT PLUS FUNCTION_NOARGS TEXT_MARKER
+dynamics: IDENT PLUS INTEGER TEXT_MARKER
Missing operator before text
diff --git a/lib/qparser/idents.ml b/lib/qparser/idents.ml
index be3d76c..a74fce2 100644
--- a/lib/qparser/idents.ml
+++ b/lib/qparser/idents.ml
@@ -99,7 +99,7 @@ let _ =
("MIN", FUNCTION T.Min);
("$MIN", FUNCTION T.Min');
("MOD", MOD);
- ("MSECSCOUNT", FUNCTION T.Msecscount);
+ ("MSECSCOUNT", FUNCTION_NOARGS T.Msecscount);
("MSG", KEYWORD T.Msg);
("NL", KEYWORD T.Nl);
("*NL", KEYWORD T.Nl');
diff --git a/lib/qparser/parser.mly b/lib/qparser/parser.mly
index 1caf962..55e729e 100644
--- a/lib/qparser/parser.mly
+++ b/lib/qparser/parser.mly
@@ -18,7 +18,7 @@
%}
%parameter<Analyzer: Qsp_syntax.Analyzer.T>
-%start <(Analyzer.context -> Analyzer.Location.t)>main
+%start<(Analyzer.context -> Analyzer.Location.t)>main
%start<(Analyzer.context -> Analyzer.Location.t)>dynamics
%on_error_reduce instruction unary_operator assignation_operator
diff --git a/lib/qparser/qsp_expression.mly b/lib/qparser/qsp_expression.mly
index f037051..0b8406c 100644
--- a/lib/qparser/qsp_expression.mly
+++ b/lib/qparser/qsp_expression.mly
@@ -1,93 +1,109 @@
%%
%public arguments(X):
- (** This rule allow the difference between elements with a single argument
- (when the separator is required) which allow to write a spectif case when
- we only have one element.
+ (** This rule allow the difference between elements with a single argument
+ (when the separator is required) which allow to write a spectif case when
+ we only have one element.
*)
- | hd = X
- COMA
- tl = separated_nonempty_list(COMA, X)
- { hd :: tl }
- (** The case where we have nothing is easy to manage here *)
- |
- { [] }
- (** The remaining case (only one argument) is handled outside of this
+ | hd = X COMA tl = separated_nonempty_list(COMA, X) { hd :: tl }
+ (** The case where we have nothing is easy to manage here *)
+ | { [] }
+
+(** The remaining case (only one argument) is handled outside of this
block: if we have a single argument we don’t have to bother with the
paren, they belongs to the expression.
*)
%inline argument(X):
- | a = delimited(L_PAREN, arguments(X), R_PAREN) { a }
- | a = X { [ a ] }
+ | a = delimited(L_PAREN, arguments(X), R_PAREN) { a }
+ | a = X { [ a ] }
(** Declare an expression *)
%public expression:
- | ex = delimited(L_PAREN, expression, R_PAREN)
- { ex }
- | op = unary_operator
- expr = expression
- { Analyzer.Expression.uoperator ~ctx:{f=(fun _ -> None)} $loc op expr }
- %prec NO
- |
- expr1 = expression
- op = binary_operator
- expr2 = expression
- { Analyzer.Expression.boperator ~ctx:{f=(fun _ -> None)} $loc op expr1 expr2 }
- | v = delimited(TEXT_MARKER, literal*, TEXT_MARKER)
- { Analyzer.Expression.literal ~ctx:{f=(fun _ -> None)} $loc v }
- | i = INTEGER { Analyzer.Expression.integer ~ctx:{f=(fun _ -> None)} $loc i }
- | v = variable { Analyzer.Expression.ident ~ctx:{f=(fun _ -> None)} v }
+ | ex = delimited(L_PAREN, expression, R_PAREN) { ex }
+ | op = unary_operator expr = expression
+ {
+ Analyzer.Expression.uoperator ~ctx:{ f = (fun _ -> None) } $loc op expr
+ }
+ %prec NO
+ | expr1 = expression op = binary_operator expr2 = expression
+ {
+ Analyzer.Expression.boperator ~ctx:{ f = (fun _ -> None) } $loc op expr1 expr2
+ }
+ | v = delimited(TEXT_MARKER, list(literal), TEXT_MARKER)
+ {
+ Analyzer.Expression.literal ~ctx:{ f = (fun _ -> None) } $loc v
+ }
+ | i = INTEGER
+ {
+ Analyzer.Expression.integer ~ctx:{ f = (fun _ -> None) } $loc i
+ }
+ | v = variable
+ { Analyzer.Expression.ident ~ctx:{ f = (fun _ -> None) } v }
%prec p_variable
- | k = FUNCTION
- arg = argument(expression)
+ | k = FUNCTION arg = argument(expression)
{
- (Analyzer.Expression.function_ ~ctx:{f=(fun _ -> None)} $loc k arg)
+ Analyzer.Expression.function_ ~ctx:{ f = (fun _ -> None) } $loc k arg
}
- | k = FUNCTION_NOARGS
+
+ (* Function without any argument can be used either
+ - without any parens
+ - or with parens but empty and with nothing inside
+ *)
+ | k = FUNCTION_NOARGS
{
- (Analyzer.Expression.function_ ~ctx:{f=(fun _ -> None)} $loc k [])
+ Analyzer.Expression.function_ ~ctx:{ f = (fun _ -> None) } $loc k []
}
+ | k = FUNCTION_NOARGS L_PAREN R_PAREN
+ {
+ Analyzer.Expression.function_ ~ctx:{ f = (fun _ -> None) } $loc k []
+ }
+
literal:
- | v = LITERAL { Qsp_syntax.T.Text v }
- | e = delimited(ENTER_EMBED, expression, LEAVE_EMBED)
+ | v = LITERAL { Qsp_syntax.T.Text v }
+ | e = delimited(ENTER_EMBED, expression, LEAVE_EMBED)
{ Qsp_syntax.T.Expression e }
unary_operator:
- | OBJ
- | NO { T.No }
- | MINUS { T.Neg }
- | PLUS { T.Add }
+ | OBJ
+ | NO
+ { T.No }
+ | MINUS { T.Neg }
+ | PLUS { T.Add }
%inline binary_operator:
- | EQUAL { T.Eq }
- | LT GT { T.Neq }
- | EXCLAMATION { T.Neq }
- | PLUS { T.Plus }
- | MINUS { T.Minus }
- | STAR { T.Product }
- | DIV { T.Div }
- | MOD { T.Mod }
- | GT { T.Gt }
- | LT { T.Lt }
- | AND { T.And }
- | GT EQUAL { T.Gte }
- | LT EQUAL { T.Lte }
- | EQUAL GT { T.Gte }
- | EQUAL LT { T.Lte }
- | OR { T.Or }
+ | EQUAL { T.Eq }
+ | LT GT { T.Neq }
+ | EXCLAMATION { T.Neq }
+ | PLUS { T.Plus }
+ | MINUS { T.Minus }
+ | STAR { T.Product }
+ | DIV { T.Div }
+ | MOD { T.Mod }
+ | GT { T.Gt }
+ | LT { T.Lt }
+ | AND { T.And }
+ | GT EQUAL { T.Gte }
+ | LT EQUAL { T.Lte }
+ | EQUAL GT { T.Gte }
+ | EQUAL LT { T.Lte }
+ | OR { T.Or }
(** Declare a variable, either in the assignation (let var = …) or as a
reference is an expression
*)
%public variable:
- | name = IDENT
- brackets = delimited(L_BRACKET, expression?, R_BRACKET)?
- {
- let index = match brackets with
- | None ->
+ | name = IDENT
+ brackets = option(
+ delimited(L_BRACKET, option(expression), R_BRACKET)
+ )
+ {
+ let index =
+ match brackets with
+ | None ->
(* No declaration, consider index at 0 *)
None
- | Some other -> other in
- Qsp_syntax.S.{ pos = $loc ; name ; index }
+ | Some other -> other
+ in
+ Qsp_syntax.S.{ pos = $loc; name; index }
}
diff --git a/test/syntax.ml b/test/syntax.ml
index ce3e89e..64c5004 100644
--- a/test/syntax.ml
+++ b/test/syntax.ml
@@ -33,10 +33,10 @@ let parse : string -> (S.pos location, Qsp_syntax.Report.t) result =
(module Parser)
Qparser.Analyzer.Location lexing context
|> Result.map (fun v ->
- (* Uncatched excteptions here, but we are in the tests…
+ (* Uncatched excteptions here, but we are in the tests…
If it’s fail here I have an error in the code. *)
- Array.get v.Qparser.Analyzer.content 0
- |> Check.get location_id |> Option.get)
+ Array.get v.Qparser.Analyzer.content 0
+ |> Check.get location_id |> Option.get)
let location : S.pos location Alcotest.testable =
let equal = equal_location (fun _ _ -> true) in
@@ -895,8 +895,21 @@ let test_stattxt () =
{ Tree.Ast.pos = _position; name = "$STATTXT"; index = None } );
]
+let test_function_no_args () =
+ let expected =
+ [
+ Tree.Ast.Declaration
+ ( _position,
+ { Tree.Ast.pos = _position; name = "VALUE"; index = None },
+ T.Eq',
+ Tree.Ast.Function (_position, T.Msecscount, []) );
+ ]
+ in
+ _test_instruction "value = msecscount" expected;
+ _test_instruction "value = msecscount()" expected
+
let test_syntax =
- ( "Syntax",
+ ( __FILE__,
[
Alcotest.test_case "Location" `Quick test_empty_location;
Alcotest.test_case "Location" `Quick test_location_without_space;
@@ -957,6 +970,7 @@ let test_syntax =
Alcotest.test_case "Precedence7" `Quick test_precedence7;
Alcotest.test_case "Precedence8" `Quick test_precedence8;
Alcotest.test_case "stattxt" `Quick test_stattxt;
+ Alcotest.test_case "stattxt" `Quick test_function_no_args;
] )
let test_comments =
diff --git a/test/syntax_error.ml b/test/syntax_error.ml
index 9d51cf3..209d3e2 100644
--- a/test/syntax_error.ml
+++ b/test/syntax_error.ml
@@ -23,7 +23,7 @@ let _test_instruction :
let _location = Printf.sprintf {|# Location
%s
------- |} literal in
- let actual = get_report @@ Syntax.parse _location and msg = literal in
+ let actual = get_report @@ Syntax.parse _location and msg = _location in
let () = Alcotest.(check' report ~msg ~expected ~actual) in
match k with None -> () | Some f -> f actual
@@ -291,7 +291,7 @@ let missing_operator () =
{ level = Error; loc = _position; message = "Missing operator before text" }
let test =
- ( "Syntax Errors",
+ ( __FILE__,
[
Alcotest.test_case "else:" `Quick else_column;
Alcotest.test_case "elseif" `Quick elseif_no_column;
@@ -305,7 +305,7 @@ let test =
Alcotest.test_case "Unknown function" `Quick unknow_function;
Alcotest.test_case "Inline elif" `Quick inline_elif;
Alcotest.test_case "Unclosed block" `Quick unclosed_block;
- Alcotest.test_case "Unclosed block" `Quick comment_as_operator;
+ Alcotest.test_case "Comment as separator" `Quick comment_as_operator;
Alcotest.test_case "Missing comparable" `Quick missing_comparable;
Alcotest.test_case "Location change" `Quick location_change;
Alcotest.test_case "Misplaced if" `Quick misplaced_if;