Skip to content

Commit ea0f43f

Browse files
authored
feat: dot notation on integer literals (#5620)
Parse num.id as `num dot id`, not `float id`, allowing `0.range(9)` etc without spurious whitespace or brackets. Introduces new token `NUM_DOT_ID` to lexer and dedicated pseudo production to grammar
1 parent 7cc684a commit ea0f43f

File tree

9 files changed

+68
-0
lines changed

9 files changed

+68
-0
lines changed

src/gen-grammar/grammar.sed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ s/<id>/ID/g
1414
/^<typ_dec> ::=/,+2d
1515
/^<parse_stab_sig> ::=/,+5d
1616
/.*PRIM.*/d
17+
/.*NUM_DOT_ID.*/d
1718
/^<bl> ::=/,+2d
1819
/^<ob> ::=/,+2d
1920
s/<start> //g

src/mo_frontend/error_reporting.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ let terminal2token (type a) (symbol : a terminal) : token =
6060
| T_NOT -> NOT
6161
| T_NEQOP -> NEQOP
6262
| T_NAT -> NAT "<nat>"
63+
| T_NUM_DOT_ID -> NUM_DOT_ID ("<num>","<id>")
6364
| T_MULOP -> MULOP
6465
| T_MULASSIGN -> MULASSIGN
6566
| T_MODULE -> MODULE

src/mo_frontend/parser.mly

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ and objblock eo s id ty dec_fields =
246246
%token TRANSIENT PERSISTENT
247247
%token<string> DOT_NUM
248248
%token<string> NAT
249+
%token<string * string> NUM_DOT_ID
249250
%token<string> FLOAT
250251
%token<Mo_values.Value.unicode> CHAR
251252
%token<bool> BOOL
@@ -673,6 +674,20 @@ exp_post(B) :
673674
{ ProjE (e, int_of_string s) @? at $sloc }
674675
| e=exp_post(B) DOT x=id
675676
{ DotE(e, x, ref None) @? at $sloc }
677+
| nid = NUM_DOT_ID
678+
{ let (num, id) = nid in
679+
let {left; right} = at $sloc in
680+
let e =
681+
LitE(ref (PreLit (num, Type.Nat))) @?
682+
{ left;
683+
right = { right with column = left.column + String.length num }}
684+
in
685+
let x =
686+
id @@
687+
{ left = { left with column = right.column - String.length id };
688+
right } in
689+
DotE(e, x, ref None) @? at $sloc
690+
}
676691
| e1=exp_post(B) inst=inst e2=exp_arg
677692
{
678693
let e2, sugar = e2 in

src/mo_frontend/printers.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ let repr_of_symbol : xsymbol -> (string * string) =
9494
| X (T T_OR) -> simple_token "or"
9595
| X (T T_OBJECT) -> simple_token "object"
9696
| X (T T_NULL) -> simple_token "null"
97+
| X (T T_NUM_DOT_ID) -> simple_token "num.id"
9798
| X (T T_NOT) -> simple_token "not"
9899
| X (T T_NEQOP) -> binop "!="
99100
| X (T T_NAT) -> "<nat>", "0"

src/mo_frontend/source_lexer.mll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ let char = '\'' (character | byte+) '\''
113113
let text = '"' character* '"'
114114
let id = ((letter | '_') ((letter | digit | '_')*))
115115
let privileged_id = "@" id
116+
let num_dot_ident =
117+
num '.' id
116118

117119
let reserved = ([^'\"''('')'';'] # space)+ (* hack for table size *)
118120

@@ -181,6 +183,11 @@ rule token mode = parse
181183

182184
| '.' (num as s) { DOT_NUM s }
183185
| nat as s { NAT s }
186+
| num_dot_ident as s {
187+
match Lib.String.split s '.' with
188+
| [n; id] -> NUM_DOT_ID (n, id)
189+
| _ -> assert false
190+
}
184191
| float as s { FLOAT s }
185192
| char as s { CHAR (char lexbuf s) }
186193
| text as s { TEXT (text lexbuf s) }

src/mo_frontend/source_token.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ type token =
116116
| ROTRASSIGN
117117
| NULL
118118
| DOT_NUM of string
119+
| NUM_DOT_ID of string * string
119120
| NAT of string
120121
| FLOAT of string
121122
| CHAR of Mo_values.Value.unicode
@@ -251,6 +252,7 @@ let to_parser_token :
251252
| ROTLASSIGN -> Ok Parser.ROTLASSIGN
252253
| ROTRASSIGN -> Ok Parser.ROTRASSIGN
253254
| NULL -> Ok Parser.NULL
255+
| NUM_DOT_ID (ns, id) -> Ok (Parser.NUM_DOT_ID (ns, id))
254256
| DOT_NUM s -> Ok (Parser.DOT_NUM s)
255257
| NAT s -> Ok (Parser.NAT s)
256258
| FLOAT s -> Ok (Parser.FLOAT s)
@@ -388,6 +390,7 @@ let string_of_parser_token = function
388390
| Parser.ROTLASSIGN -> "ROTLASSIGN"
389391
| Parser.ROTRASSIGN -> "ROTRASSIGN"
390392
| Parser.NULL -> "NULL"
393+
| Parser.NUM_DOT_ID _ -> "NUM_DOT_IDENT of string * string"
391394
| Parser.DOT_NUM _ -> "DOT_NUM of string"
392395
| Parser.NAT _ -> "NAT of string"
393396
| Parser.FLOAT _ -> "FLOAT of string"

test/fail/nat-dot.mo

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// test parsing dot notation on integral literals works
2+
module Nat {
3+
4+
public func toText(self : Nat) : Text { "" };
5+
6+
};
7+
8+
module Int {
9+
10+
public func toText(self : Int) : Text { "" };
11+
12+
};
13+
14+
module Float {
15+
16+
public func toText(self : Float) : Text { "" };
17+
18+
};
19+
20+
21+
ignore 0.toText(); // Nat.toText()
22+
23+
ignore 0 .toText(); // Nat.toText()
24+
25+
ignore (+0).toText(); // Int.toText()
26+
27+
ignore (-0).toText(); // Int.toText()
28+
29+
ignore 0.0.toText(); // Float.toText()
30+
31+
ignore 0..toText(); // Float.toText()
32+
33+
34+
ignore +0 .toText(); // dubious (error)
35+
ignore -0 .toText(); // dubious (error)

test/fail/ok/nat-dot.tc.ok

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
nat-dot.mo:34.8-34.20: type error [M0059], operator is not defined for operand type
2+
Text
3+
nat-dot.mo:35.8-35.20: type error [M0059], operator is not defined for operand type
4+
Text

test/fail/ok/nat-dot.tc.ret.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Return code 1

0 commit comments

Comments
 (0)