Skip to content

Commit

Permalink
Merge pull request #1086 from informalsystems/1081/simple-record-fiel…
Browse files Browse the repository at this point in the history
…d-ids

Require record fields to be simple identifiers
  • Loading branch information
Shon Feder authored Aug 2, 2023
2 parents cc195bc + def3f05 commit 8feb3d8
Show file tree
Hide file tree
Showing 21 changed files with 1,778 additions and 1,354 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `quint repl` produces an evaluation trace on errors too (#1056)
- `S.setOfMaps(Int).oneOf()` is now supported (#1060)
- `quint run` produces a friendlier message when it meets a `const` (#1050)

### Changed

- **Breaking**: the behavior of `oneOf` has changed, existing seed values for `quint test`
- The behavior of `oneOf` has changed, existing seed values for `quint test`
can exhibit different behavior than before (#1060)
- `quint run` produces a friendlier message when it meets a `const` (#1050)
- Record field labels that include `::` are now illegal and raise a syntax error
(#1086)

### Deprecated
### Removed
Expand Down
81 changes: 52 additions & 29 deletions quint/src/generated/Quint.g4
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,29 @@
*/
grammar Quint;

@header {
// Used for forming errors
import { quintErrorToString } from '../quintError'

}
// entry point for the parser
modules : module+ EOF;

module : DOCCOMMENT* 'module' IDENTIFIER '{' documentedUnit* '}';
module : DOCCOMMENT* 'module' qualId '{' documentedUnit* '}';
documentedUnit : DOCCOMMENT* unit;

// a module unit
unit : 'const' IDENTIFIER ':' type # const
| 'var' IDENTIFIER ':' type # var
| 'assume' identOrHole '=' expr # assume
| instanceMod # instance
| operDef # oper
| typeDef # typeDefs
| importMod # importDef
| exportMod # exportDef
unit : 'const' qualId ':' type # const
| 'var' qualId ':' type # var
| 'assume' identOrHole '=' expr # assume
| instanceMod # instance
| operDef # oper
| typeDef # typeDefs
| importMod # importDef
| exportMod # exportDef
// https://github.com/informalsystems/quint/issues/378
//| 'nondet' IDENTIFIER (':' type)? '=' expr ';'? expr {
//| 'nondet' qualId (':' type)? '=' expr ';'? expr {
// const m = "QNT007: 'nondet' is only allowed inside actions"
// this.notifyErrorListeners(m)
//} # nondetError
Expand All @@ -46,11 +52,11 @@ operDef : qualifier normalCallName
;

typeDef
: 'type' IDENTIFIER # typeAbstractDef
| 'type' IDENTIFIER '=' type # typeAliasDef
: 'type' qualId # typeAbstractDef
| 'type' qualId '=' type # typeAliasDef
;

nondetOperDef : 'nondet' IDENTIFIER (':' type)? '=' expr ';'?;
nondetOperDef : 'nondet' qualId (':' type)? '=' expr ';'?;

qualifier : 'val'
| 'def'
Expand Down Expand Up @@ -79,9 +85,9 @@ instanceMod : // creating an instance and importing all names introduced in th
('from' fromSource)?
;

moduleName : IDENTIFIER;
name: IDENTIFIER;
qualifiedName : IDENTIFIER;
moduleName : qualId;
name: qualId;
qualifiedName : qualId;
fromSource: STRING;

// Types in Type System 1.2 of Apalache, which supports discriminated unions
Expand All @@ -96,17 +102,20 @@ type : <assoc=right> type '->' type # typeFun
| 'int' # typeInt
| 'str' # typeStr
| 'bool' # typeBool
| IDENTIFIER # typeConstOrVar
| qualId # typeConstOrVar
| '(' type ')' # typeParen
;

typeUnionRecOne : '|' '{' IDENTIFIER ':' STRING (',' row)? ','? '}'
typeUnionRecOne : '|' '{' qualId ':' STRING (',' row)? ','? '}'
;

row : | (IDENTIFIER ':' type ',')* ((IDENTIFIER ':' type) (',' | '|' (IDENTIFIER))?)?
| '|' (IDENTIFIER)
row : (rowLabel ':' type ',')* ((rowLabel ':' type) (',' | '|' (rowVar=IDENTIFIER))?)?
| '|' (rowVar=IDENTIFIER)
;

rowLabel : simpleId["record"] ;


// A Quint expression. The order matters, it defines the priority.
// Wherever possible, we keep the same order of operators as in TLA+.
// We are also trying to be consistent with mainstream languages, e.g.,
Expand All @@ -129,7 +138,7 @@ expr: // apply a built-in operator via the dot notation
| expr op=(PLUS | MINUS) expr # plusMinus
// standard relations
| expr op=(GT | LT | GE | LE | NE | EQ) expr # relations
| IDENTIFIER '\'' ASGN expr # asgn
| qualId '\'' ASGN expr # asgn
| expr '=' expr {
const m = "QNT006: unexpected '=', did you mean '=='?"
this.notifyErrorListeners(m)
Expand All @@ -146,7 +155,7 @@ expr: // apply a built-in operator via the dot notation
('|' STRING ':' parameter '=>' expr)+ # match
| 'all' '{' expr (',' expr)* ','? '}' # actionAll
| 'any' '{' expr (',' expr)* ','? '}' # actionAny
| ( IDENTIFIER | INT | BOOL | STRING) # literalOrId
| ( qualId | INT | BOOL | STRING) # literalOrId
// a tuple constructor, the form tup(...) is just an operator call
| '(' expr ',' expr (',' expr)* ','? ')' # tuple
// short-hand syntax for pairs, mainly designed for maps
Expand Down Expand Up @@ -176,31 +185,31 @@ lambda: parameter '=>' expr


// an identifier or a hole '_'
identOrHole : '_' | IDENTIFIER
identOrHole : '_' | qualId
;

parameter: identOrHole;

// an identifier or a star '*'
identOrStar : '*' | IDENTIFIER
identOrStar : '*' | qualId
;

argList : expr (',' expr)*
;

recElem : IDENTIFIER ':' expr
recElem : simpleId["record"] ':' expr
| '...' expr
;

// operators in the normal call may use a few reserved names,
// which are not recognized as identifiers.
normalCallName : IDENTIFIER
normalCallName : qualId
| op=(AND | OR | IFF | IMPLIES | SET | LIST | MAP)
;

// A few infix operators may be called via lhs.oper(rhs),
// without causing any ambiguity.
nameAfterDot : IDENTIFIER
nameAfterDot : qualId
| op=(AND | OR | IFF | IMPLIES)
;

Expand All @@ -214,6 +223,21 @@ operator: (AND | OR | IFF | IMPLIES |
literal: (STRING | BOOL | INT)
;

// A (possibly) qualified identifier, like `Foo` or `Foo::bar`
qualId : IDENTIFIER ('::' IDENTIFIER)* ;
// An unqualified identifier that raises an error if a qualId is supplied
simpleId[context: string]
: IDENTIFIER
| qualId {
const err = quintErrorToString(
{ code: 'QNT008',
message: "Identifiers in a " + $context + " cannot be qualified with '::'. Found " + $qualId.text + "."
},
)
this.notifyErrorListeners(err)
}
;

// TOKENS

// literals
Expand Down Expand Up @@ -250,8 +274,7 @@ LPAREN : '(' ;
RPAREN : ')' ;

// other TLA+ identifiers
IDENTIFIER : SIMPLE_IDENTIFIER | SIMPLE_IDENTIFIER '::' IDENTIFIER ;
SIMPLE_IDENTIFIER : ([a-zA-Z][a-zA-Z0-9_]*|[_][a-zA-Z0-9_]+) ;
IDENTIFIER : ([a-zA-Z][a-zA-Z0-9_]*|[_][a-zA-Z0-9_]+) ;

DOCCOMMENT : '///' .*? '\n';

Expand Down
9 changes: 6 additions & 3 deletions quint/src/generated/Quint.interp

Large diffs are not rendered by default.

99 changes: 50 additions & 49 deletions quint/src/generated/Quint.tokens

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions quint/src/generated/QuintLexer.interp

Large diffs are not rendered by default.

Loading

0 comments on commit 8feb3d8

Please sign in to comment.