GrammaticalFramework / gf-core

Grammatical Framework core: compiler, shell & runtimes
https://www.grammaticalframework.org
Other
131 stars 35 forks source link

Getting "unsupported token gluing" with nonexhaustive pattern #52

Open inariksit opened 4 years ago

inariksit commented 4 years ago

Minimal test grammar

abstract Test = {

cat S ;
fun testS : S ;
}

And here's a concrete syntax that causes an unsupported token gluing error unnecessarily.

concrete TestCnc of Test = open Prelude in {

lincat S = SS ;
lin testS = mkSS "test" ;

oper
  mkSS : Str -> SS ;
  mkSS str = case str of {
    x + "foo" => ss (x + "bar")
  } ;
}

Error

The error I get is this:

- compiling TestCnc.gf... gf: 8-10: In mkSS: unsupported token gluing: str + "bar"
CallStack (from HasCallStack):
  error, called at src/compiler/GF/Compile/Compute/ConcreteNew.hs:294:32 in gf-3.10.3-78vkYEvqjDa3tJH3g2tXyo:GF.Compile.Compute.ConcreteNew

Now I completely agree that the concrete syntax should cause an error, but just not about unsupported token gluing.

Minimal variations that don't cause the error

I found three ways to get rid of the misguided token gluing error:

a) Add a catch-all case after the x + "foo" case.

No errors anymore.

  mkSS str = case str of {
     x + "foo" => ss (x + "bar") ;
     x         => ss (x + "baz") } ;

b) Don't use the variable x on the right-hand side, but use the variable str instead.

This gives the expected error gf: Internal error in GeneratePMCFG: evalTerm ("test").

  mkSS str = case str of {
     x + "foo" => ss (str + "bar") } ;

c) Use the variable x on the RHS but don't glue the string "bar".

This gives the expected error gf: Internal error in GeneratePMCFG: evalTerm ("test").

  mkSS str = case str of {
     x + "foo" => ss x } ;

Link to grammars

The grammars are found in this gist: https://gist.github.com/inariksit/78a1929c4e98c5cc9d6ea693f7d0127f.

rnd0101 commented 4 years ago

I also hit this with:


  add_refl_postfix : Str -> Str
--    = \s -> case Predef.dp 1 s of {#vowel => s + "сь" ; _ => s + "ся"};
--    = \s -> s ++ BIND ++ "ся" ;
    = \s -> s + "ся" ;

where

  passivate : VerbForms -> VerbForms
    = \vf -> case vf.refl of {
      Reflexive => vf ;
      NonReflexive => {
        inf=add_refl_postfix vf.inf ;
        prsg1=add_refl_postfix vf.prsg1 ;
        prsg2=add_refl_postfix vf.prsg2 ;
        prsg3=add_refl_postfix vf.prsg3 ;
        prpl1=add_refl_postfix vf.prpl1 ;
        prpl2=add_refl_postfix vf.prpl2 ;
        prpl3=add_refl_postfix vf.prpl3 ;
        futsg1=add_refl_postfix vf.futsg1 ;
        futsg2=add_refl_postfix vf.futsg2 ;
        futsg3=add_refl_postfix vf.futsg3 ;
        futpl1=add_refl_postfix vf.futpl1 ;
        futpl2=add_refl_postfix vf.futpl2 ;
        futpl3=add_refl_postfix vf.futpl3 ;
        psgm=add_refl_postfix vf.psgm ;
        psgf=add_refl_postfix vf.psgf ;
        psgn=add_refl_postfix vf.psgn ;
        ppl=add_refl_postfix vf.ppl ;
        isg2=add_refl_postfix vf.isg2 ;
        ipl1=add_refl_postfix vf.ipl1 ;
        ipl2=add_refl_postfix vf.ipl2 ;
        asp=vf.asp ;
        refl=vf.refl ;
        tran=vf.tran
      }
    } ;

where

  VerbForms : Type = {
    inf,
    prsg1, prsg2, prsg3, prpl1, prpl2, prpl3,
    futsg1, futsg2, futsg3, futpl1, futpl2, futpl3,
    psgm, psgf, psgn, ppl,
    isg2, ipl1, ipl2 : Str ;
    asp : Aspect ;
    refl : Reflexivity ;
    tran : Transitivity
  } ;

error message: In add_refl_postfix: unsupported token gluing: s.futpl1 + "ся"

and in one case it was even:

Internal error in Compute.ConcreteNew: Applying Predef.dp: Expected a value of type String, got VP (VGen 0 []) (LIdent (Id {rawId2utf8 = "futpl1"}))

(that is when first variant uncommented)

Using BIND or glue functions eliminates the problem for the simpl + case, but not for dp.

Also with latest gf-core master:

CallStack (from HasCallStack):
  error, called at src/compiler/GF/Compile/Compute/ConcreteNew.hs:588:13 in gf-3.10.4-E482sCKHVk4HKPfObWJaiR:GF.Compile.Compute.ConcreteNew
inariksit commented 4 years ago

@rnd0101: All your versions look perfectly fine, as for exhaustive patterns.

case Predef.dp 1 s of {
    #vowel => s + "сь" ; 
     _          => s + "ся"};

The other two don't even pattern match, and this one above has a catch-all, so it's not like my example without one (case str of { x + "foo" => …}).

Where do you call the passivate oper? If you call it from a lin that takes arguments, like PassV2, then the error is accurate: you may not pattern match, use +, dp, tk nor their aliases.

BIND is allowed, so if you want to continue with your approach, you need to store a version without the last character of all the stems instead of calling dp at runtime. (Or store the full form from the beginning, if the stems aren't used for any other forms?)

rnd0101 commented 4 years ago

@inariksit Got it! Yes, I call passivate from there, and actually "stepped on the same rake". I wish gf had a noticeably different syntax for PCFG and "Turing-complete" paths... Or some IDE, which highlights them differently... Isn't there any analogue of "pre" for "post" (not even sure it's theoretically possible)?

rnd0101 commented 4 years ago

I am thinking if I can store just some "reflexive postfix schemas" (I already noticed they are not that diverse) and use them with BIND, that will hopefully save considerable amount of memory as they are not per verb...