Skip to content

Commit 815424c

Browse files
committed
Fix pexp parser to do left-associativity, not right. Closes #130.
1 parent 1a8d609 commit 815424c

File tree

3 files changed

+91
-36
lines changed

3 files changed

+91
-36
lines changed

src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
489489
obj-recursion.rs \
490490
obj-return-polytypes.rs \
491491
obj-with-vec.rs \
492+
operator-associativity.rs \
492493
output-slot-variants.rs \
493494
pred.rs \
494495
preempt.rs \

src/boot/fe/pexp.ml

Lines changed: 86 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -718,142 +718,192 @@ and parse_negation_pexp (ps:pstate) : pexp =
718718

719719
(* Binops are all left-associative, *)
720720
(* so we factor out some of the parsing code here. *)
721-
and binop_rhs
721+
and binop_build
722722
(ps:pstate)
723723
(name:string)
724724
(apos:pos)
725-
(lhs:pexp)
726725
(rhs_parse_fn:pstate -> pexp)
726+
(lhs:pexp)
727+
(step_fn:pexp -> pexp)
727728
(op:Ast.binop)
728729
: pexp =
729730
bump ps;
730731
let rhs = (ctxt (name ^ " rhs") rhs_parse_fn ps) in
731732
let bpos = lexpos ps in
732-
span ps apos bpos (PEXP_binop (op, lhs, rhs))
733+
let node = span ps apos bpos (PEXP_binop (op, lhs, rhs)) in
734+
step_fn node
733735

734736

735737
and parse_factor_pexp (ps:pstate) : pexp =
736738
let name = "factor pexp" in
737739
let apos = lexpos ps in
738740
let lhs = ctxt (name ^ " lhs") parse_negation_pexp ps in
741+
let build = binop_build ps name apos parse_negation_pexp in
742+
let rec step accum =
739743
match peek ps with
740-
STAR -> binop_rhs ps name apos lhs parse_factor_pexp Ast.BINOP_mul
741-
| SLASH -> binop_rhs ps name apos lhs parse_factor_pexp Ast.BINOP_div
742-
| PERCENT -> binop_rhs ps name apos lhs parse_factor_pexp Ast.BINOP_mod
743-
| _ -> lhs
744+
STAR -> build accum step Ast.BINOP_mul
745+
| SLASH -> build accum step Ast.BINOP_div
746+
| PERCENT -> build accum step Ast.BINOP_mod
747+
| _ -> accum
748+
in
749+
step lhs
744750

745751

746752
and parse_term_pexp (ps:pstate) : pexp =
747753
let name = "term pexp" in
748754
let apos = lexpos ps in
749755
let lhs = ctxt (name ^ " lhs") parse_factor_pexp ps in
756+
let build = binop_build ps name apos parse_factor_pexp in
757+
let rec step accum =
750758
match peek ps with
751-
PLUS -> binop_rhs ps name apos lhs parse_term_pexp Ast.BINOP_add
752-
| MINUS -> binop_rhs ps name apos lhs parse_term_pexp Ast.BINOP_sub
753-
| _ -> lhs
759+
PLUS -> build accum step Ast.BINOP_add
760+
| MINUS -> build accum step Ast.BINOP_sub
761+
| _ -> accum
762+
in
763+
step lhs
754764

755765

756766
and parse_shift_pexp (ps:pstate) : pexp =
757767
let name = "shift pexp" in
758768
let apos = lexpos ps in
759769
let lhs = ctxt (name ^ " lhs") parse_term_pexp ps in
770+
let build = binop_build ps name apos parse_term_pexp in
771+
let rec step accum =
760772
match peek ps with
761-
LSL -> binop_rhs ps name apos lhs parse_shift_pexp Ast.BINOP_lsl
762-
| LSR -> binop_rhs ps name apos lhs parse_shift_pexp Ast.BINOP_lsr
763-
| ASR -> binop_rhs ps name apos lhs parse_shift_pexp Ast.BINOP_asr
764-
| _ -> lhs
773+
LSL -> build accum step Ast.BINOP_lsl
774+
| LSR -> build accum step Ast.BINOP_lsr
775+
| ASR -> build accum step Ast.BINOP_asr
776+
| _ -> accum
777+
in
778+
step lhs
765779

766780

767781
and parse_and_pexp (ps:pstate) : pexp =
768782
let name = "and pexp" in
769783
let apos = lexpos ps in
770784
let lhs = ctxt (name ^ " lhs") parse_shift_pexp ps in
785+
let build = binop_build ps name apos parse_shift_pexp in
786+
let rec step accum =
771787
match peek ps with
772-
AND -> binop_rhs ps name apos lhs parse_and_pexp Ast.BINOP_and
773-
| _ -> lhs
788+
AND -> build accum step Ast.BINOP_and
789+
| _ -> accum
790+
in
791+
step lhs
774792

775793

776794
and parse_xor_pexp (ps:pstate) : pexp =
777795
let name = "xor pexp" in
778796
let apos = lexpos ps in
779797
let lhs = ctxt (name ^ " lhs") parse_and_pexp ps in
798+
let build = binop_build ps name apos parse_and_pexp in
799+
let rec step accum =
780800
match peek ps with
781-
CARET -> binop_rhs ps name apos lhs parse_xor_pexp Ast.BINOP_xor
782-
| _ -> lhs
801+
CARET -> build accum step Ast.BINOP_xor
802+
| _ -> accum
803+
in
804+
step lhs
783805

784806

785807
and parse_or_pexp (ps:pstate) : pexp =
786808
let name = "or pexp" in
787809
let apos = lexpos ps in
788810
let lhs = ctxt (name ^ " lhs") parse_xor_pexp ps in
811+
let build = binop_build ps name apos parse_xor_pexp in
812+
let rec step accum =
789813
match peek ps with
790-
OR -> binop_rhs ps name apos lhs parse_or_pexp Ast.BINOP_or
791-
| _ -> lhs
814+
OR -> build accum step Ast.BINOP_or
815+
| _ -> accum
816+
in
817+
step lhs
792818

793819

794820
and parse_relational_pexp (ps:pstate) : pexp =
795821
let name = "relational pexp" in
796822
let apos = lexpos ps in
797823
let lhs = ctxt (name ^ " lhs") parse_or_pexp ps in
824+
let build = binop_build ps name apos parse_or_pexp in
825+
let rec step accum =
798826
match peek ps with
799-
LT -> binop_rhs ps name apos lhs parse_relational_pexp Ast.BINOP_lt
800-
| LE -> binop_rhs ps name apos lhs parse_relational_pexp Ast.BINOP_le
801-
| GE -> binop_rhs ps name apos lhs parse_relational_pexp Ast.BINOP_ge
802-
| GT -> binop_rhs ps name apos lhs parse_relational_pexp Ast.BINOP_gt
803-
| _ -> lhs
827+
LT -> build accum step Ast.BINOP_lt
828+
| LE -> build accum step Ast.BINOP_le
829+
| GE -> build accum step Ast.BINOP_ge
830+
| GT -> build accum step Ast.BINOP_gt
831+
| _ -> accum
832+
in
833+
step lhs
804834

805835

806836
and parse_equality_pexp (ps:pstate) : pexp =
807837
let name = "equality pexp" in
808838
let apos = lexpos ps in
809839
let lhs = ctxt (name ^ " lhs") parse_relational_pexp ps in
840+
let build = binop_build ps name apos parse_relational_pexp in
841+
let rec step accum =
810842
match peek ps with
811-
EQEQ -> binop_rhs ps name apos lhs parse_equality_pexp Ast.BINOP_eq
812-
| NE -> binop_rhs ps name apos lhs parse_equality_pexp Ast.BINOP_ne
813-
| _ -> lhs
843+
EQEQ -> build accum step Ast.BINOP_eq
844+
| NE -> build accum step Ast.BINOP_ne
845+
| _ -> accum
846+
in
847+
step lhs
814848

815849

816850
and parse_andand_pexp (ps:pstate) : pexp =
817851
let name = "andand pexp" in
818852
let apos = lexpos ps in
819853
let lhs = ctxt (name ^ " lhs") parse_equality_pexp ps in
854+
let rec step accum =
820855
match peek ps with
821856
ANDAND ->
822857
bump ps;
823-
let rhs = parse_andand_pexp ps in
858+
let rhs = parse_equality_pexp ps in
824859
let bpos = lexpos ps in
825-
span ps apos bpos (PEXP_lazy_and (lhs, rhs))
860+
let node = span ps apos bpos (PEXP_lazy_and (accum, rhs)) in
861+
step node
826862

827-
| _ -> lhs
863+
| _ -> accum
864+
in
865+
step lhs
828866

829867

830868
and parse_oror_pexp (ps:pstate) : pexp =
831869
let name = "oror pexp" in
832870
let apos = lexpos ps in
833871
let lhs = ctxt (name ^ " lhs") parse_andand_pexp ps in
872+
let rec step accum =
834873
match peek ps with
835874
OROR ->
836875
bump ps;
837-
let rhs = parse_oror_pexp ps in
876+
let rhs = parse_andand_pexp ps in
838877
let bpos = lexpos ps in
839-
span ps apos bpos (PEXP_lazy_or (lhs, rhs))
878+
let node = span ps apos bpos (PEXP_lazy_or (accum, rhs)) in
879+
step node
880+
881+
| _ -> accum
882+
in
883+
step lhs
840884

841-
| _ -> lhs
842885

843886
and parse_as_pexp (ps:pstate) : pexp =
844887
let apos = lexpos ps in
845888
let pexp = ctxt "as pexp" parse_oror_pexp ps in
889+
let rec step accum =
846890
match peek ps with
847891
AS ->
848892
bump ps;
849893
let tapos = lexpos ps in
850894
let t = parse_ty ps in
851895
let bpos = lexpos ps in
852896
let t = span ps tapos bpos t in
897+
let node =
853898
span ps apos bpos
854-
(PEXP_unop ((Ast.UNOP_cast t), pexp))
899+
(PEXP_unop ((Ast.UNOP_cast t), accum))
900+
in
901+
step node
902+
903+
| _ -> accum
904+
in
905+
step pexp
855906

856-
| _ -> pexp
857907

858908
and parse_pexp (ps:pstate) : pexp =
859909
parse_as_pexp ps
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Testcase for issue #130, operator associativity.
2+
fn main() -> () {
3+
check ((3 * 5 / 2) == 7);
4+
}

0 commit comments

Comments
 (0)