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

[BUG] Could not parse TLC configuration in BlockingQueue.cfg: string matching regex '\z' expected but '{' found #208

Closed
lemmy opened this issue Aug 21, 2020 · 9 comments · Fixed by #328
Assignees
Labels
bug parser Issues related to parsing the SANY semantic graph
Milestone

Comments

@lemmy
Copy link
Contributor

lemmy commented Aug 21, 2020

kuppe@mkuppe-z440:~/src/TLA/blockingqueue$ ../apalache/bin/apalache-mc check BlockingQueue.tla
# Tool home: /home/mkuppe/src/TLA/apalache
# Package:   /home/mkuppe/src/TLA/apalache/mod-distribution/target/apalache-pkg-0.7.3-SNAPSHOT-full.jar
# JVM args: -Xmx4096m -Djava.library.path=/home/mkuppe/src/TLA/apalache/3rdparty/lib  -DTLA-Library=/home/mkuppe/src/TLA/apalache/src/tla:/home/mkuppe/src/TLA/blockingqueue/
#
# APALACHE version 0.7.3-SNAPSHOT build v0.7.0-28-gdd171c8
#
# WARNING: This tool is in the experimental stage.
#          Please report bugs at: [https://github.com/informalsystems/apalache/issues]

Checker options: filename=BlockingQueue.tla, init=, next=, inv=   I@19:04:13.850
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/home/mkuppe/src/TLA/apalache/mod-distribution/target/apalache-pkg-0.7.3-SNAPSHOT-full.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
PASS #0: SanyParser                                               I@19:04:14.139
Parsing file /home/mkuppe/src/TLA/blockingqueue/BlockingQueue.tla
Parsing file /tmp/Naturals.tla
Parsing file /tmp/Sequences.tla
Parsing file /tmp/FiniteSets.tla
Parsing file /home/mkuppe/src/TLA/blockingqueue/TLAPS.tla
PASS #1: ConfigurationPass                                        I@19:04:14.482
  > Loading TLC configuration from BlockingQueue.cfg              I@19:04:14.483
Configuration error (see the manual):   > Could not parse TLC configuration in BlockingQueue.cfg: string matching regex '\z' expected but '{' found E@19:04:14.523
It took me 0 days  0 hours  0 min  0 sec                          I@19:04:14.524
Total time: 0.727 sec                                             I@19:04:14.524
EXITCODE: ERROR (99)

mkuppe@mkuppe-z440:~/src/TLA/blockingqueue$ cat BlockingQueue.cfg 
\* SPECIFICATION
CONSTANTS
    BufCapacity = 3
    Producers = {p1,p2,p3,p4}
    Consumers = {c1,c2,c3}

SPECIFICATION FairSpec

INVARIANT Invariant
INVARIANT TypeInv

PROPERTY Starvation

mkuppe@mkuppe-z440:~/src/TLA/blockingqueue$ uname -a
Linux mkuppe-z440 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

mkuppe@mkuppe-z440:~/src/TLA/blockingqueue$ java -version
openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10-post-Ubuntu-0ubuntu120.04)
OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Ubuntu-0ubuntu120.04, mixed mode, sharing)
--------------------------- MODULE BlockingQueue ---------------------------
EXTENDS Naturals, Sequences, FiniteSets

CONSTANTS Producers,   (* the (nonempty) set of producers                       *)
          Consumers,   (* the (nonempty) set of consumers                       *)
          BufCapacity  (* the maximum number of messages in the bounded buffer  *)

ASSUME Assumption ==
       /\ Producers # {}                      (* at least one producer *)
       /\ Consumers # {}                      (* at least one consumer *)
       /\ Producers \intersect Consumers = {} (* no thread is both consumer and producer *)
       /\ BufCapacity \in (Nat \ {0})         (* buffer capacity is at least 1 *)
       
-----------------------------------------------------------------------------

VARIABLES buffer, waitSet
vars == <<buffer, waitSet>>

RunningThreads == (Producers \cup Consumers) \ waitSet

NotifyOther(t) == 
          LET S == IF t \in Producers THEN waitSet \ Producers ELSE waitSet \ Consumers
          IN IF S # {}
             THEN \E x \in S : waitSet' = waitSet \ {x}
             ELSE UNCHANGED waitSet

(* @see java.lang.Object#wait *)
Wait(t) == /\ waitSet' = waitSet \cup {t}
           /\ UNCHANGED <<buffer>>
           
-----------------------------------------------------------------------------

Put(t, d) ==
/\ t \notin waitSet
/\ \/ /\ Len(buffer) < BufCapacity
      /\ buffer' = Append(buffer, d)
      /\ NotifyOther(t)
   \/ /\ Len(buffer) = BufCapacity
      /\ Wait(t)
      
Get(t) ==
/\ t \notin waitSet
/\ \/ /\ buffer # <<>>
      /\ buffer' = Tail(buffer)
      /\ NotifyOther(t)
   \/ /\ buffer = <<>>
      /\ Wait(t)

-----------------------------------------------------------------------------

(* Initially, the buffer is empty and no thread is waiting. *)
Init == /\ buffer = <<>>
        /\ waitSet = {}

(* Then, pick a thread out of all running threads and have it do its thing. *)
Next == \/ \E p \in Producers: Put(p, p) \* Add some data to buffer
        \/ \E c \in Consumers: Get(c)

-----------------------------------------------------------------------------

(* TLA+ is untyped, thus lets verify the range of some values in each state. *)
TypeInv == /\ buffer \in Seq(Producers)
           /\ Len(buffer) \in 0..BufCapacity
           /\ waitSet \in SUBSET (Producers \cup Consumers)

(* No Deadlock *)
Invariant == waitSet # (Producers \cup Consumers)

-----------------------------------------------------------------------------

MySeq(P) == UNION {[1..n -> P] : n \in 0..BufCapacity}

INSTANCE TLAPS

Spec == Init /\ [][Next]_vars

(* Whitelist all the known facts and definitions (except IInv below) *)
USE Assumption DEF vars, RunningThreads,
                   Init, Next, Spec,
                   Put, Get,
                   Wait, NotifyOther,
                   TypeInv, Invariant

\* TypeInv will be a conjunct of the inductive invariant, so prove it inductive.
\* An invariant I is inductive, iff Init => I and I /\ [Next]_vars => I. Note
\* though, that TypeInv itself won't imply Invariant though!  TypeInv alone
\* does not help us prove Invariant.
\* Luckily, TLAPS does not require us to decompose the proof into substeps. 
LEMMA TypeCorrect == Spec => []TypeInv
<1>1. Init => TypeInv BY SMT 
<1>2. TypeInv /\ [Next]_vars => TypeInv' BY SMT 
<1>. QED BY <1>1, <1>2, PTL

\* The naive thing to do is to check if the conjunct of TypeInv /\ Invariant
\* is inductive.
IInv == /\ TypeInv!2
        /\ TypeInv!3
        /\ Invariant
        \* When the buffer is empty, a consumer will be added to the waitSet.
        \* However, this does not crate a deadlock, because at least one producer
        \* will not be in the waitSet.
        /\ buffer = <<>> => \E p \in Producers : p \notin waitSet
        \* Vice versa, when buffer is full, a producer will be added to waitSet,
        \* but at least one consumer won't be in waitSet.
        /\ Len(buffer) = BufCapacity => \E c \in Consumers : c \notin waitSet

THEOREM DeadlockFreedom == Spec => []Invariant
<1>1. Init => IInv BY SMT DEF IInv
<1>2. IInv /\ [Next]_vars => IInv' BY DEF IInv
<1>3. IInv => Invariant  BY DEF IInv
<1>4. QED BY <1>1,<1>2,<1>3,PTL

MCIInv == TypeInv!1 /\ IInv

-----------------------------------------------------------------------------

PutEnabled == \A p \in Producers : ENABLED Put(p, p)

FairSpec == Spec /\ WF_vars(Next) 
                 /\ \A p \in Producers : WF_vars(Put(p, p)) 

(* All producers will continuously be serviced. For this to be violated,    *)
(* ASSUME Cardinality(Producers) > 1 has to hold (a single producer cannot  *)
(* starve itself).                                                          *)
Starvation == \A p \in Producers: []<>(<<Put(p, p)>>_vars)

=============================================================================
@lemmy lemmy added the bug label Aug 21, 2020
@shonfeder
Copy link
Contributor

shonfeder commented Aug 24, 2020

Just some notes as I use this bug report as an opportunity to dig into the code a bit.

So here's the error being raised:

https://github.com/informalsystems/apalache/blob/dd171c8417b7ec651b6116abe2261f2c9abc9406/tla-pp/src/main/scala/at/forsyte/apalache/tla/pp/passes/ConfigurationPassImpl.scala#L128-L130

I suspect it's coming from this part of the lexer:

https://github.com/informalsystems/apalache/blob/dd171c8417b7ec651b6116abe2261f2c9abc9406/tla-import/src/main/scala/at/forsyte/apalache/io/tlc/config/TlcConfigLexer.scala#L28-L41

After including the parser location in the error message, it became clear the parser is failing on the last line here, at the opening {:

\* SPECIFICATION
CONSTANTS
    BufCapacity = 3
    Producers = {p1,p2,p3,p4}

(See https://github.com/lemmy/BlockingQueue/blob/3a66f46f6f5703f2863f71baaf0aedaaee58836f/BlockingQueue.cfg#L1-L4 for the source.)

Indeed, the lexer defined in TlcConfigLexer.scala is not equipped to recognize sets at all. Presumably this pertains to the "limited syntax" noted in the manual https://github.com/informalsystems/apalache/blob/unstable/docs/manual.md#54-tlc-configuration-file ?

If this is currently a necessary limitation, then we can at least improve the documentation and the error reporting to help guide the user. If this is not a necessary limitation, I'd be interested in adding the support for handling sets in cfg files.

@lemmy
Copy link
Contributor Author

lemmy commented Aug 24, 2020

Why wasn't it possible to reuse TLC's config parser?

@konnov
Copy link
Collaborator

konnov commented Aug 25, 2020

Our conjecture was that the users are not writing .cfg files by hand. Rather they use whatever is produced by the TLA+ Toolbox. This obviously does not apply to the power users :-)

It looks to me that the ability to define sets in .cfg is redundant, as one can do that directly in TLA+. That is what TLA+ Toolbox is doing, right?

@konnov
Copy link
Collaborator

konnov commented Aug 25, 2020

@lemmy, could you point us to the TLC's config parser, so we could evaluate the efforts of integrating with it?

@lemmy
Copy link
Contributor Author

lemmy commented Aug 25, 2020

The VScode extension that appears to be popular, especially amongst new users, requires users to write the config file by hand. I believe it's considered a feature.

tlc2.tool.impl.ModelConfig (it has few dependencies)

@konnov konnov added this to the v0.12.0-user-care milestone Sep 23, 2020
@konnov konnov added the parser Issues related to parsing the SANY semantic graph label Oct 26, 2020
@konnov konnov self-assigned this Nov 10, 2020
@konnov
Copy link
Collaborator

konnov commented Nov 10, 2020

@lemmy, I am looking at ModelConfig right now. The following statements are not specified in Leslie's book:

  • ALIAS
  • POSTCONDITION
  • CHECK_DEADLOCK

Are they documented anywhere? I can guess what CHECK_DEADLOCK is supposed to mean, but what about the other two?

@lemmy
Copy link
Contributor Author

lemmy commented Nov 10, 2020

@konnov
Copy link
Collaborator

konnov commented Nov 10, 2020

I guess, ALIAS is supposed to be similar to alias in shell? From what I see in the description, it is more like DISPLAY or SHOW. But if it is already in production, that is not important.

@lemmy
Copy link
Contributor Author

lemmy commented Nov 10, 2020

ALIAS is actually inspired by SQL's ALIAS, but VIEW would have been the best term. Unfortunately, VIEW was already taken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug parser Issues related to parsing the SANY semantic graph
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants