diff options
Diffstat (limited to 'src/runtime')
45 files changed, 9381 insertions, 0 deletions
diff --git a/src/runtime/c/Makefile b/src/runtime/c/Makefile new file mode 100644 index 000000000..72ac7ea79 --- /dev/null +++ b/src/runtime/c/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CFLAGS += -O2 -W -Wall + +.PHONY: all clean + +all: libgfcc.a + +libgfcc.a: gfcc-tree.o gfcc-term.o + ar r $@ $^ + +gfcc-tree.o: gfcc-tree.c gfcc-tree.h + $(CC) $(CFLAGS) -c -o $@ $< + +gfcc-term.o: gfcc-term.c gfcc-term.h + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + -rm -f libgfcc.a + -rm -f *.o diff --git a/src/runtime/c/gfcc-term.c b/src/runtime/c/gfcc-term.c new file mode 100644 index 000000000..b427479e6 --- /dev/null +++ b/src/runtime/c/gfcc-term.c @@ -0,0 +1,203 @@ +#include "gfcc-term.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +static void *buffer = NULL; +static size_t current; + +extern void term_alloc_pool(size_t size) { + if (buffer == NULL) + buffer = malloc(size); + current = 0; +} + +extern void term_free_pool() { + if (buffer != NULL) + free(buffer); + buffer = NULL; +} + +extern void *term_alloc(size_t size) { + void *off = buffer + current; + current += size; + return off; +} + +static inline Term *create_term(TermType type, int n) { + Term *t = (Term*)term_alloc(sizeof(Term) + n * sizeof(Term *)); + t->type = type; + t->value.size = n; /* FIXME: hack! */ + return t; +} + +extern Term *term_array(int n, ...) { + Term *t = create_term(TERM_ARRAY, n); + va_list ap; + int i; + + va_start(ap, n); + for (i = 0; i < n; i++) { + term_set_child(t, i, va_arg(ap, Term *)); + } + va_end(ap); + + return t; +} + +extern Term *term_seq(int n, ...) { + Term *t = create_term(TERM_SEQUENCE, n); + va_list ap; + int i; + + va_start(ap, n); + for (i = 0; i < n; i++) { + term_set_child(t, i, va_arg(ap, Term *)); + } + va_end(ap); + + return t; +} + +extern Term *term_variants(int n, ...) { + Term *t = create_term(TERM_VARIANTS, n); + va_list ap; + int i; + + va_start(ap, n); + for (i = 0; i < n; i++) { + term_set_child(t, i, va_arg(ap, Term *)); + } + va_end(ap); + + return t; +} + +extern Term *term_glue(int n, ...) { + Term *t = create_term(TERM_GLUE, n); + va_list ap; + int i; + + va_start(ap, n); + for (i = 0; i < n; i++) { + term_set_child(t, i, va_arg(ap, Term *)); + } + va_end(ap); + + return t; +} + +extern Term *term_rp(Term *t1, Term *t2) { + Term *t = create_term(TERM_RECORD_PARAM, 2); + term_set_child(t, 0, t1); + term_set_child(t, 1, t2); + return t; +} + +extern Term *term_suffix(const char *pref, Term *suf) { + Term *t = create_term(TERM_SUFFIX_TABLE, 2); + term_set_child(t,0,term_str(pref)); + term_set_child(t,1,suf); + return t; +} + +extern Term *term_str(const char *s) { + Term *t = create_term(TERM_STRING, 0); + t->value.string_value = s; + return t; +} + +extern Term *term_int(int i) { + Term *t = create_term(TERM_INTEGER,0); + t->value.integer_value = i; + return t; +} + +extern Term *term_meta() { + return create_term(TERM_META, 0); +} + + + +extern Term *term_sel_int(Term *t, int i) { + switch (t->type) { + case TERM_ARRAY: + return term_get_child(t,i); + case TERM_SUFFIX_TABLE: + return term_glue(2, + term_get_child(t,0), + term_sel_int(term_get_child(t,1),i)); + case TERM_META: + return t; + default: + fprintf(stderr,"Error: term_sel_int %d %d\n", t->type, i); + exit(1); + return NULL; + } +} + +extern Term *term_sel(Term *t1, Term *t2) { + switch (t2->type) { + case TERM_INTEGER: + return term_sel_int(t1, t2->value.integer_value); + case TERM_RECORD_PARAM: + return term_sel(t1,term_get_child(t2,0)); + case TERM_META: + return term_sel_int(t1,0); + default: + fprintf(stderr,"Error: term_sel %d %d\n", t1->type, t2->type); + exit(1); + return 0; + } +} + + + +static void term_print_sep(FILE *stream, Term *t, const char *sep) { + int n = t->value.size; + int i; + + for (i = 0; i < n; i++) { + term_print(stream, term_get_child(t,i)); + if (i < n-1) { + fputs(sep, stream); + } + } +} + +extern void term_print(FILE *stream, Term *t) { + switch (t->type) { + case TERM_ARRAY: + term_print(stream, term_get_child(t,0)); + break; + case TERM_SEQUENCE: + term_print_sep(stream, t, " "); + break; + case TERM_VARIANTS: + term_print_sep(stream, t, "/"); + break; + case TERM_GLUE: + term_print_sep(stream, t, ""); + break; + case TERM_RECORD_PARAM: + term_print(stream, term_get_child(t,0)); + break; + case TERM_SUFFIX_TABLE: + term_print(stream, term_get_child(t,0)); + term_print(stream, term_get_child(t,1)); + break; + case TERM_META: + fputs("?", stream); + break; + case TERM_STRING: + fputs(t->value.string_value, stream); + break; + case TERM_INTEGER: + fprintf(stream, "%d", t->value.integer_value); + break; + default: + fprintf(stderr,"Error: term_print %d\n", t->type); + exit(1); + } +} diff --git a/src/runtime/c/gfcc-term.h b/src/runtime/c/gfcc-term.h new file mode 100644 index 000000000..d1307259d --- /dev/null +++ b/src/runtime/c/gfcc-term.h @@ -0,0 +1,65 @@ +#ifndef GFCC_TERM_H +#define GFCC_TERM_H + +#include <stdio.h> + +typedef enum { + /* size = variable */ + TERM_ARRAY, + TERM_SEQUENCE, + TERM_VARIANTS, + TERM_GLUE, + /* size = 2 */ + TERM_RECORD_PARAM, + TERM_SUFFIX_TABLE, + /* size = 0 */ + TERM_META, + TERM_STRING, + TERM_INTEGER +} TermType; + +struct Term_ { + TermType type; + union { + const char *string_value; + int integer_value; + int size; + } value; + struct Term_ *args[0]; +}; + +typedef struct Term_ Term; + + + +static inline Term *term_get_child(Term *t, int n) { + return t->args[n]; +} + +static inline void term_set_child(Term *t, int n, Term *c) { + t->args[n] = c; +} + +extern void term_alloc_pool(size_t size); +extern void term_free_pool(); +extern void *term_alloc(size_t size); + + +extern Term *term_array(int n, ...); +extern Term *term_seq(int n, ...); +extern Term *term_variants(int n, ...); +extern Term *term_glue(int n, ...); + +extern Term *term_rp(Term *t1, Term *t2); +extern Term *term_suffix(const char *pref, Term *suf); +extern Term *term_str(const char *s); +extern Term *term_int(int i); +extern Term *term_meta(); + +extern Term *term_sel_int(Term *t, int i); +extern Term *term_sel(Term *t1, Term *t2); + + +extern void term_print(FILE *stream, Term *t); + +#endif diff --git a/src/runtime/c/gfcc-tree.c b/src/runtime/c/gfcc-tree.c new file mode 100644 index 000000000..6cd8759be --- /dev/null +++ b/src/runtime/c/gfcc-tree.c @@ -0,0 +1,61 @@ +#include "gfcc-tree.h" + +#include <stdlib.h> + + +extern int arity(Tree *t) { + switch (t->type) { + case ATOM_STRING: + case ATOM_INTEGER: + case ATOM_DOUBLE: + case ATOM_META: + return 0; + default: + return t->value.size; + } +} + +static Tree *create_tree(atom_type c, int n) { + Tree *t = (Tree *)malloc(sizeof(Tree) + n * sizeof(Tree *)); + t->type = c; + return t; +} + +extern Tree *tree_string(const char *s) { + Tree *t = create_tree(ATOM_STRING, 0); + t->value.string_value = s; + return t; +} + +extern Tree *tree_integer(int i) { + Tree *t = create_tree(ATOM_INTEGER, 0); + t->value.integer_value = i; + return t; +} + +extern Tree *tree_double(double d) { + Tree *t = create_tree(ATOM_DOUBLE, 0); + t->value.double_value = d; + return t; +} + +extern Tree *tree_meta() { + return create_tree(ATOM_META, 0); +} + +extern Tree *tree_fun(atom_type f, int n) { + Tree *t = create_tree(f, n); + t->value.size = n; + return t; +} + + +extern void tree_free(Tree *t) { + int n = arity(t); + int i; + + for (i = 0; i < n; i++) { + tree_free(tree_get_child(t,i)); + } + free(t); +} diff --git a/src/runtime/c/gfcc-tree.h b/src/runtime/c/gfcc-tree.h new file mode 100644 index 000000000..cc8f0fcab --- /dev/null +++ b/src/runtime/c/gfcc-tree.h @@ -0,0 +1,49 @@ +#ifndef GFCC_TREE_H +#define GFCC_TREE_H + +typedef enum { + ATOM_STRING, + ATOM_INTEGER, + ATOM_DOUBLE, + ATOM_META, + ATOM_FIRST_FUN +} atom_type; + +struct Tree_{ + atom_type type; + union { + const char *string_value; + int integer_value; + double double_value; + int size; + } value; + struct Tree_ *args[0]; +}; + +typedef struct Tree_ Tree; + +static inline Tree *tree_get_child(Tree *t, int n) { + return t->args[n]; +} + +static inline void tree_set_child(Tree *t, int n, Tree *a) { + t->args[n] = a; +} + +extern int arity(Tree *t); + + +extern Tree *tree_string(const char *s); + +extern Tree *tree_integer(int i); + +extern Tree *tree_double(double d); + +extern Tree *tree_meta(); + +extern Tree *tree_fun(atom_type f, int n); + + +extern void tree_free(Tree *t); + +#endif diff --git a/src/runtime/haskell/Data/Binary.hs b/src/runtime/haskell/Data/Binary.hs new file mode 100644 index 000000000..786f5a09e --- /dev/null +++ b/src/runtime/haskell/Data/Binary.hs @@ -0,0 +1,791 @@ +{-# LANGUAGE CPP, FlexibleInstances, FlexibleContexts #-} +----------------------------------------------------------------------------- +-- | +-- Module : Data.Binary +-- Copyright : Lennart Kolmodin +-- License : BSD3-style (see LICENSE) +-- +-- Maintainer : Lennart Kolmodin <kolmodin@dtek.chalmers.se> +-- Stability : unstable +-- Portability : portable to Hugs and GHC. Requires the FFI and some flexible instances +-- +-- Binary serialisation of Haskell values to and from lazy ByteStrings. +-- The Binary library provides methods for encoding Haskell values as +-- streams of bytes directly in memory. The resulting @ByteString@ can +-- then be written to disk, sent over the network, or futher processed +-- (for example, compressed with gzip). +-- +-- The 'Binary' package is notable in that it provides both pure, and +-- high performance serialisation. +-- +-- Values are always encoded in network order (big endian) form, and +-- encoded data should be portable across machine endianess, word size, +-- or compiler version. For example, data encoded using the Binary class +-- could be written from GHC, and read back in Hugs. +-- +----------------------------------------------------------------------------- + +module Data.Binary ( + + -- * The Binary class + Binary(..) + + -- $example + + -- * The Get and Put monads + , Get + , Put + + -- * Useful helpers for writing instances + , putWord8 + , getWord8 + + -- * Binary serialisation + , encode -- :: Binary a => a -> ByteString + , decode -- :: Binary a => ByteString -> a + + -- * IO functions for serialisation + , encodeFile -- :: Binary a => FilePath -> a -> IO () + , decodeFile -- :: Binary a => FilePath -> IO a + +-- Lazy put and get +-- , lazyPut +-- , lazyGet + + , module Data.Word -- useful + + ) where + +#include "MachDeps.h" + +import Data.Word + +import Data.Binary.Put +import Data.Binary.Get + +import Control.Monad +import Control.Exception +import Foreign +import System.IO + +import Data.ByteString.Lazy (ByteString) +import qualified Data.ByteString.Lazy as L + +import Data.Char (chr,ord) +import Data.List (unfoldr) + +-- And needed for the instances: +import qualified Data.ByteString as B +import qualified Data.Map as Map +import qualified Data.Set as Set +import qualified Data.IntMap as IntMap +import qualified Data.IntSet as IntSet +import qualified Data.Ratio as R + +import qualified Data.Tree as T + +import Data.Array.Unboxed + +-- +-- This isn't available in older Hugs or older GHC +-- +#if __GLASGOW_HASKELL__ >= 606 +import qualified Data.Sequence as Seq +import qualified Data.Foldable as Fold +#endif + +------------------------------------------------------------------------ + +-- | The @Binary@ class provides 'put' and 'get', methods to encode and +-- decode a Haskell value to a lazy ByteString. It mirrors the Read and +-- Show classes for textual representation of Haskell types, and is +-- suitable for serialising Haskell values to disk, over the network. +-- +-- For parsing and generating simple external binary formats (e.g. C +-- structures), Binary may be used, but in general is not suitable +-- for complex protocols. Instead use the Put and Get primitives +-- directly. +-- +-- Instances of Binary should satisfy the following property: +-- +-- > decode . encode == id +-- +-- That is, the 'get' and 'put' methods should be the inverse of each +-- other. A range of instances are provided for basic Haskell types. +-- +class Binary t where + -- | Encode a value in the Put monad. + put :: t -> Put + -- | Decode a value in the Get monad + get :: Get t + +-- $example +-- To serialise a custom type, an instance of Binary for that type is +-- required. For example, suppose we have a data structure: +-- +-- > data Exp = IntE Int +-- > | OpE String Exp Exp +-- > deriving Show +-- +-- We can encode values of this type into bytestrings using the +-- following instance, which proceeds by recursively breaking down the +-- structure to serialise: +-- +-- > instance Binary Exp where +-- > put (IntE i) = do put (0 :: Word8) +-- > put i +-- > put (OpE s e1 e2) = do put (1 :: Word8) +-- > put s +-- > put e1 +-- > put e2 +-- > +-- > get = do t <- get :: Get Word8 +-- > case t of +-- > 0 -> do i <- get +-- > return (IntE i) +-- > 1 -> do s <- get +-- > e1 <- get +-- > e2 <- get +-- > return (OpE s e1 e2) +-- +-- Note how we write an initial tag byte to indicate each variant of the +-- data type. +-- +-- We can simplify the writing of 'get' instances using monadic +-- combinators: +-- +-- > get = do tag <- getWord8 +-- > case tag of +-- > 0 -> liftM IntE get +-- > 1 -> liftM3 OpE get get get +-- +-- The generation of Binary instances has been automated by a script +-- using Scrap Your Boilerplate generics. Use the script here: +-- <http://darcs.haskell.org/binary/tools/derive/BinaryDerive.hs>. +-- +-- To derive the instance for a type, load this script into GHCi, and +-- bring your type into scope. Your type can then have its Binary +-- instances derived as follows: +-- +-- > $ ghci -fglasgow-exts BinaryDerive.hs +-- > *BinaryDerive> :l Example.hs +-- > *Main> deriveM (undefined :: Drinks) +-- > +-- > instance Binary Main.Drinks where +-- > put (Beer a) = putWord8 0 >> put a +-- > put Coffee = putWord8 1 +-- > put Tea = putWord8 2 +-- > put EnergyDrink = putWord8 3 +-- > put Water = putWord8 4 +-- > put Wine = putWord8 5 +-- > put Whisky = putWord8 6 +-- > get = do +-- > tag_ <- getWord8 +-- > case tag_ of +-- > 0 -> get >>= \a -> return (Beer a) +-- > 1 -> return Coffee +-- > 2 -> return Tea +-- > 3 -> return EnergyDrink +-- > 4 -> return Water +-- > 5 -> return Wine +-- > 6 -> return Whisky +-- > +-- +-- To serialise this to a bytestring, we use 'encode', which packs the +-- data structure into a binary format, in a lazy bytestring +-- +-- > > let e = OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) +-- > > let v = encode e +-- +-- Where 'v' is a binary encoded data structure. To reconstruct the +-- original data, we use 'decode' +-- +-- > > decode v :: Exp +-- > OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) +-- +-- The lazy ByteString that results from 'encode' can be written to +-- disk, and read from disk using Data.ByteString.Lazy IO functions, +-- such as hPutStr or writeFile: +-- +-- > > writeFile "/tmp/exp.txt" (encode e) +-- +-- And read back with: +-- +-- > > readFile "/tmp/exp.txt" >>= return . decode :: IO Exp +-- > OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) +-- +-- We can also directly serialise a value to and from a Handle, or a file: +-- +-- > > v <- decodeFile "/tmp/exp.txt" :: IO Exp +-- > OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) +-- +-- And write a value to disk +-- +-- > > encodeFile "/tmp/a.txt" v +-- + +------------------------------------------------------------------------ +-- Wrappers to run the underlying monad + +-- | Encode a value using binary serialisation to a lazy ByteString. +-- +encode :: Binary a => a -> ByteString +encode = runPut . put +{-# INLINE encode #-} + +-- | Decode a value from a lazy ByteString, reconstructing the original structure. +-- +decode :: Binary a => ByteString -> a +decode = runGet get + +------------------------------------------------------------------------ +-- Convenience IO operations + +-- | Lazily serialise a value to a file +-- +-- This is just a convenience function, it's defined simply as: +-- +-- > encodeFile f = B.writeFile f . encode +-- +-- So for example if you wanted to compress as well, you could use: +-- +-- > B.writeFile f . compress . encode +-- +encodeFile :: Binary a => FilePath -> a -> IO () +encodeFile f v = L.writeFile f (encode v) + +-- | Lazily reconstruct a value previously written to a file. +-- +-- This is just a convenience function, it's defined simply as: +-- +-- > decodeFile f = return . decode =<< B.readFile f +-- +-- So for example if you wanted to decompress as well, you could use: +-- +-- > return . decode . decompress =<< B.readFile f +-- +decodeFile :: Binary a => FilePath -> IO a +decodeFile f = bracket (openBinaryFile f ReadMode) hClose $ \h -> do + s <- L.hGetContents h + evaluate $ runGet get s + +-- needs bytestring 0.9.1.x to work + +------------------------------------------------------------------------ +-- Lazy put and get + +-- lazyPut :: (Binary a) => a -> Put +-- lazyPut a = put (encode a) + +-- lazyGet :: (Binary a) => Get a +-- lazyGet = fmap decode get + +------------------------------------------------------------------------ +-- Simple instances + +-- The () type need never be written to disk: values of singleton type +-- can be reconstructed from the type alone +instance Binary () where + put () = return () + get = return () + +-- Bools are encoded as a byte in the range 0 .. 1 +instance Binary Bool where + put = putWord8 . fromIntegral . fromEnum + get = liftM (toEnum . fromIntegral) getWord8 + +-- Values of type 'Ordering' are encoded as a byte in the range 0 .. 2 +instance Binary Ordering where + put = putWord8 . fromIntegral . fromEnum + get = liftM (toEnum . fromIntegral) getWord8 + +------------------------------------------------------------------------ +-- Words and Ints + +-- Words8s are written as bytes +instance Binary Word8 where + put = putWord8 + get = getWord8 + +-- Words16s are written as 2 bytes in big-endian (network) order +instance Binary Word16 where + put = putWord16be + get = getWord16be + +-- Words32s are written as 4 bytes in big-endian (network) order +instance Binary Word32 where + put = putWord32be + get = getWord32be + +-- Words64s are written as 8 bytes in big-endian (network) order +instance Binary Word64 where + put = putWord64be + get = getWord64be + +-- Int8s are written as a single byte. +instance Binary Int8 where + put i = put (fromIntegral i :: Word8) + get = liftM fromIntegral (get :: Get Word8) + +-- Int16s are written as a 2 bytes in big endian format +instance Binary Int16 where + put i = put (fromIntegral i :: Word16) + get = liftM fromIntegral (get :: Get Word16) + +-- Int32s are written as a 4 bytes in big endian format +instance Binary Int32 where + put i = put (fromIntegral i :: Word32) + get = liftM fromIntegral (get :: Get Word32) + +-- Int64s are written as a 4 bytes in big endian format +instance Binary Int64 where + put i = put (fromIntegral i :: Word64) + get = liftM fromIntegral (get :: Get Word64) + +------------------------------------------------------------------------ + +-- Words are written as sequence of bytes. The last bit of each +-- byte indicates whether there are more bytes to be read +instance Binary Word where + put i | i <= 0x7f = do put a + | i <= 0x3fff = do put (a .|. 0x80) + put b + | i <= 0x1fffff = do put (a .|. 0x80) + put (b .|. 0x80) + put c + | i <= 0xfffffff = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put d +#if WORD_SIZE_IN_BITS < 64 + | otherwise = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put e +#else + | i <= 0x7ffffffff = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put e + | i <= 0x3ffffffffff = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put (e .|. 0x80) + put f + | i <= 0x1ffffffffffff = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put (e .|. 0x80) + put (f .|. 0x80) + put g + | i <= 0xffffffffffffff = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put (e .|. 0x80) + put (f .|. 0x80) + put (g .|. 0x80) + put h + | i <= 0xffffffffffffff = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put (e .|. 0x80) + put (f .|. 0x80) + put (g .|. 0x80) + put h + | i <= 0x7fffffffffffffff = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put (e .|. 0x80) + put (f .|. 0x80) + put (g .|. 0x80) + put (h .|. 0x80) + put j + | otherwise = do put (a .|. 0x80) + put (b .|. 0x80) + put (c .|. 0x80) + put (d .|. 0x80) + put (e .|. 0x80) + put (f .|. 0x80) + put (g .|. 0x80) + put (h .|. 0x80) + put (j .|. 0x80) + put k +#endif + where + a = fromIntegral ( i .&. 0x7f) :: Word8 + b = fromIntegral (shiftR i 7 .&. 0x7f) :: Word8 + c = fromIntegral (shiftR i 14 .&. 0x7f) :: Word8 + d = fromIntegral (shiftR i 21 .&. 0x7f) :: Word8 + e = fromIntegral (shiftR i 28 .&. 0x7f) :: Word8 + f = fromIntegral (shiftR i 35 .&. 0x7f) :: Word8 + g = fromIntegral (shiftR i 42 .&. 0x7f) :: Word8 + h = fromIntegral (shiftR i 49 .&. 0x7f) :: Word8 + j = fromIntegral (shiftR i 56 .&. 0x7f) :: Word8 + k = fromIntegral (shiftR i 63 .&. 0x7f) :: Word8 + + get = do i <- getWord8 + (if i <= 0x7f + then return (fromIntegral i) + else do n <- get + return $ (n `shiftL` 7) .|. (fromIntegral (i .&. 0x7f))) + +-- Int has the same representation as Word +instance Binary Int where + put i = put (fromIntegral i :: Word) + get = liftM fromIntegral (get :: Get Word) + +------------------------------------------------------------------------ +-- +-- Portable, and pretty efficient, serialisation of Integer +-- + +-- Fixed-size type for a subset of Integer +type SmallInt = Int32 + +-- Integers are encoded in two ways: if they fit inside a SmallInt, +-- they're written as a byte tag, and that value. If the Integer value +-- is too large to fit in a SmallInt, it is written as a byte array, +-- along with a sign and length field. + +instance Binary Integer where + + {-# INLINE put #-} + put n | n >= lo && n <= hi = do + putWord8 0 + put (fromIntegral n :: SmallInt) -- fast path + where + lo = fromIntegral (minBound :: SmallInt) :: Integer + hi = fromIntegral (maxBound :: SmallInt) :: Integer + + put n = do + putWord8 1 + put sign + put (unroll (abs n)) -- unroll the bytes + where + sign = fromIntegral (signum n) :: Word8 + + {-# INLINE get #-} + get = do + tag <- get :: Get Word8 + case tag of + 0 -> liftM fromIntegral (get :: Get SmallInt) + _ -> do sign <- get + bytes <- get + let v = roll bytes + return $! if sign == (1 :: Word8) then v else - v + +-- +-- Fold and unfold an Integer to and from a list of its bytes +-- +unroll :: Integer -> [Word8] +unroll = unfoldr step + where + step 0 = Nothing + step i = Just (fromIntegral i, i `shiftR` 8) + +roll :: [Word8] -> Integer +roll = foldr unstep 0 + where + unstep b a = a `shiftL` 8 .|. fromIntegral b + +{- + +-- +-- An efficient, raw serialisation for Integer (GHC only) +-- + +-- TODO This instance is not architecture portable. GMP stores numbers as +-- arrays of machine sized words, so the byte format is not portable across +-- architectures with different endianess and word size. + +import Data.ByteString.Base (toForeignPtr,unsafePackAddress, memcpy) +import GHC.Base hiding (ord, chr) +import GHC.Prim +import GHC.Ptr (Ptr(..)) +import GHC.IOBase (IO(..)) + +instance Binary Integer where + put (S# i) = putWord8 0 >> put (I# i) + put (J# s ba) = do + putWord8 1 + put (I# s) + put (BA ba) + + get = do + b <- getWord8 + case b of + 0 -> do (I# i#) <- get + return (S# i#) + _ -> do (I# s#) <- get + (BA a#) <- get + return (J# s# a#) + +instance Binary ByteArray where + + -- Pretty safe. + put (BA ba) = + let sz = sizeofByteArray# ba -- (primitive) in *bytes* + addr = byteArrayContents# ba + bs = unsafePackAddress (I# sz) addr + in put bs -- write as a ByteString. easy, yay! + + -- Pretty scary. Should be quick though + get = do + (fp, off, n@(I# sz)) <- liftM toForeignPtr get -- so decode a ByteString + assert (off == 0) $ return $ unsafePerformIO $ do + (MBA arr) <- newByteArray sz -- and copy it into a ByteArray# + let to = byteArrayContents# (unsafeCoerce# arr) -- urk, is this safe? + withForeignPtr fp $ \from -> memcpy (Ptr to) from (fromIntegral n) + freezeByteArray arr + +-- wrapper for ByteArray# +data ByteArray = BA {-# UNPACK #-} !ByteArray# +data MBA = MBA {-# UNPACK #-} !(MutableByteArray# RealWorld) + +newByteArray :: Int# -> IO MBA +newByteArray sz = IO $ \s -> + case newPinnedByteArray# sz s of { (# s', arr #) -> + (# s', MBA arr #) } + +freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray +freezeByteArray arr = IO $ \s -> + case unsafeFreezeByteArray# arr s of { (# s', arr' #) -> + (# s', BA arr' #) } + +-} + +instance (Binary a,Integral a) => Binary (R.Ratio a) where + put r = put (R.numerator r) >> put (R.denominator r) + get = liftM2 (R.%) get get + +------------------------------------------------------------------------ + +-- Char is serialised as UTF-8 +instance Binary Char where + put a | c <= 0x7f = put (fromIntegral c :: Word8) + | c <= 0x7ff = do put (0xc0 .|. y) + put (0x80 .|. z) + | c <= 0xffff = do put (0xe0 .|. x) + put (0x80 .|. y) + put (0x80 .|. z) + | c <= 0x10ffff = do put (0xf0 .|. w) + put (0x80 .|. x) + put (0x80 .|. y) + put (0x80 .|. z) + | otherwise = error "Not a valid Unicode code point" + where + c = ord a + z, y, x, w :: Word8 + z = fromIntegral (c .&. 0x3f) + y = fromIntegral (shiftR c 6 .&. 0x3f) + x = fromIntegral (shiftR c 12 .&. 0x3f) + w = fromIntegral (shiftR c 18 .&. 0x7) + + get = do + let getByte = liftM (fromIntegral :: Word8 -> Int) get + shiftL6 = flip shiftL 6 :: Int -> Int + w <- getByte + r <- case () of + _ | w < 0x80 -> return w + | w < 0xe0 -> do + x <- liftM (xor 0x80) getByte + return (x .|. shiftL6 (xor 0xc0 w)) + | w < 0xf0 -> do + x <- liftM (xor 0x80) getByte + y <- liftM (xor 0x80) getByte + return (y .|. shiftL6 (x .|. shiftL6 + (xor 0xe0 w))) + | otherwise -> do + x <- liftM (xor 0x80) getByte + y <- liftM (xor 0x80) getByte + z <- liftM (xor 0x80) getByte + return (z .|. shiftL6 (y .|. shiftL6 + (x .|. shiftL6 (xor 0xf0 w)))) + return $! chr r + +------------------------------------------------------------------------ +-- Instances for the first few tuples + +instance (Binary a, Binary b) => Binary (a,b) where + put (a,b) = put a >> put b + get = liftM2 (,) get get + +instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where + put (a,b,c) = put a >> put b >> put c + get = liftM3 (,,) get get get + +instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where + put (a,b,c,d) = put a >> put b >> put c >> put d + get = liftM4 (,,,) get get get get + +instance (Binary a, Binary b, Binary c, Binary d, Binary e) => Binary (a,b,c,d,e) where + put (a,b,c,d,e) = put a >> put b >> put c >> put d >> put e + get = liftM5 (,,,,) get get get get get + +-- +-- and now just recurse: +-- + +instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f) + => Binary (a,b,c,d,e,f) where + put (a,b,c,d,e,f) = put (a,(b,c,d,e,f)) + get = do (a,(b,c,d,e,f)) <- get ; return (a,b,c,d,e,f) + +instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f, Binary g) + => Binary (a,b,c,d,e,f,g) where + put (a,b,c,d,e,f,g) = put (a,(b,c,d,e,f,g)) + get = do (a,(b,c,d,e,f,g)) <- get ; return (a,b,c,d,e,f,g) + +instance (Binary a, Binary b, Binary c, Binary d, Binary e, + Binary f, Binary g, Binary h) + => Binary (a,b,c,d,e,f,g,h) where + put (a,b,c,d,e,f,g,h) = put (a,(b,c,d,e,f,g,h)) + get = do (a,(b,c,d,e,f,g,h)) <- get ; return (a,b,c,d,e,f,g,h) + +instance (Binary a, Binary b, Binary c, Binary d, Binary e, + Binary f, Binary g, Binary h, Binary i) + => Binary (a,b,c,d,e,f,g,h,i) where + put (a,b,c,d,e,f,g,h,i) = put (a,(b,c,d,e,f,g,h,i)) + get = do (a,(b,c,d,e,f,g,h,i)) <- get ; return (a,b,c,d,e,f,g,h,i) + +instance (Binary a, Binary b, Binary c, Binary d, Binary e, + Binary f, Binary g, Binary h, Binary i, Binary j) + => Binary (a,b,c,d,e,f,g,h,i,j) where + put (a,b,c,d,e,f,g,h,i,j) = put (a,(b,c,d,e,f,g,h,i,j)) + get = do (a,(b,c,d,e,f,g,h,i,j)) <- get ; return (a,b,c,d,e,f,g,h,i,j) + +------------------------------------------------------------------------ +-- Container types + +instance Binary a => Binary [a] where + put l = put (length l) >> mapM_ put l + get = do n <- get :: Get Int + xs <- replicateM n get + return xs + +instance (Binary a) => Binary (Maybe a) where + put Nothing = putWord8 0 + put (Just x) = putWord8 1 >> put x + get = do + w <- getWord8 + case w of + 0 -> return Nothing + _ -> liftM Just get + +instance (Binary a, Binary b) => Binary (Either a b) where + put (Left a) = putWord8 0 >> put a + put (Right b) = putWord8 1 >> put b + get = do + w <- getWord8 + case w of + 0 -> liftM Left get + _ -> liftM Right get + +------------------------------------------------------------------------ +-- ByteStrings (have specially efficient instances) + +instance Binary B.ByteString where + put bs = do put (B.length bs) + putByteString bs + get = get >>= getByteString + +-- +-- Using old versions of fps, this is a type synonym, and non portable +-- +-- Requires 'flexible instances' +-- +instance Binary ByteString where + put bs = do put (fromIntegral (L.length bs) :: Int) + putLazyByteString bs + get = get >>= getLazyByteString + +------------------------------------------------------------------------ +-- Maps and Sets + +instance (Ord a, Binary a) => Binary (Set.Set a) where + put s = put (Set.size s) >> mapM_ put (Set.toAscList s) + get = liftM Set.fromDistinctAscList get + +instance (Ord k, Binary k, Binary e) => Binary (Map.Map k e) where + put m = put (Map.size m) >> mapM_ put (Map.toAscList m) + get = liftM Map.fromDistinctAscList get + +instance Binary IntSet.IntSet where + put s = put (IntSet.size s) >> mapM_ put (IntSet.toAscList s) + get = liftM IntSet.fromDistinctAscList get + +instance (Binary e) => Binary (IntMap.IntMap e) where + put m = put (IntMap.size m) >> mapM_ put (IntMap.toAscList m) + get = liftM IntMap.fromDistinctAscList get + +------------------------------------------------------------------------ +-- Queues and Sequences + +#if __GLASGOW_HASKELL__ >= 606 +-- +-- This is valid Hugs, but you need the most recent Hugs +-- + +instance (Binary e) => Binary (Seq.Seq e) where + put s = put (Seq.length s) >> Fold.mapM_ put s + get = do n <- get :: Get Int + rep Seq.empty n get + where rep xs 0 _ = return $! xs + rep xs n g = xs `seq` n `seq` do + x <- g + rep (xs Seq.|> x) (n-1) g + +#endif + +------------------------------------------------------------------------ +-- Floating point + +instance Binary Double where + put d = put (decodeFloat d) + get = liftM2 encodeFloat get get + +instance Binary Float where + put f = put (decodeFloat f) + get = liftM2 encodeFloat get get + +------------------------------------------------------------------------ +-- Trees + +instance (Binary e) => Binary (T.Tree e) where + put (T.Node r s) = put r >> put s + get = liftM2 T.Node get get + +------------------------------------------------------------------------ +-- Arrays + +instance (Binary i, Ix i, Binary e) => Binary (Array i e) where + put a = do + put (bounds a) + put (rangeSize $ bounds a) -- write the length + mapM_ put (elems a) -- now the elems. + get = do + bs <- get + n <- get -- read the length + xs <- replicateM n get -- now the elems. + return (listArray bs xs) + +-- +-- The IArray UArray e constraint is non portable. Requires flexible instances +-- +instance (Binary i, Ix i, Binary e, IArray UArray e) => Binary (UArray i e) where + put a = do + put (bounds a) + put (rangeSize $ bounds a) -- now write the length + mapM_ put (elems a) + get = do + bs <- get + n <- get + xs <- replicateM n get + return (listArray bs xs) diff --git a/src/runtime/haskell/Data/Binary/Builder.hs b/src/runtime/haskell/Data/Binary/Builder.hs new file mode 100644 index 000000000..cccbe6fa4 --- /dev/null +++ b/src/runtime/haskell/Data/Binary/Builder.hs @@ -0,0 +1,426 @@ +{-# LANGUAGE CPP #-} +{-# OPTIONS_GHC -fglasgow-exts #-} +-- for unboxed shifts + +----------------------------------------------------------------------------- +-- | +-- Module : Data.Binary.Builder +-- Copyright : Lennart Kolmodin, Ross Paterson +-- License : BSD3-style (see LICENSE) +-- +-- Maintainer : Lennart Kolmodin <kolmodin@dtek.chalmers.se> +-- Stability : experimental +-- Portability : portable to Hugs and GHC +-- +-- Efficient construction of lazy bytestrings. +-- +----------------------------------------------------------------------------- + +#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) +#include "MachDeps.h" +#endif + +module Data.Binary.Builder ( + + -- * The Builder type + Builder + , toLazyByteString + + -- * Constructing Builders + , empty + , singleton + , append + , fromByteString -- :: S.ByteString -> Builder + , fromLazyByteString -- :: L.ByteString -> Builder + + -- * Flushing the buffer state + , flush + + -- * Derived Builders + -- ** Big-endian writes + , putWord16be -- :: Word16 -> Builder + , putWord32be -- :: Word32 -> Builder + , putWord64be -- :: Word64 -> Builder + + -- ** Little-endian writes + , putWord16le -- :: Word16 -> Builder + , putWord32le -- :: Word32 -> Builder + , putWord64le -- :: Word64 -> Builder + + -- ** Host-endian, unaligned writes + , putWordhost -- :: Word -> Builder + , putWord16host -- :: Word16 -> Builder + , putWord32host -- :: Word32 -> Builder + , putWord64host -- :: Word64 -> Builder + + ) where + +import Foreign +import Data.Monoid +import Data.Word +import qualified Data.ByteString as S +import qualified Data.ByteString.Lazy as L + +#ifdef BYTESTRING_IN_BASE +import Data.ByteString.Base (inlinePerformIO) +import qualified Data.ByteString.Base as S +#else +import Data.ByteString.Internal (inlinePerformIO) +import qualified Data.ByteString.Internal as S +import qualified Data.ByteString.Lazy.Internal as L +#endif + +#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) +import GHC.Base +import GHC.Word (Word32(..),Word16(..),Word64(..)) + +#if WORD_SIZE_IN_BITS < 64 && __GLASGOW_HASKELL__ >= 608 +import GHC.Word (uncheckedShiftRL64#) +#endif +#endif + +------------------------------------------------------------------------ + +-- | A 'Builder' is an efficient way to build lazy 'L.ByteString's. +-- There are several functions for constructing 'Builder's, but only one +-- to inspect them: to extract any data, you have to turn them into lazy +-- 'L.ByteString's using 'toLazyByteString'. +-- +-- Internally, a 'Builder' constructs a lazy 'L.Bytestring' by filling byte +-- arrays piece by piece. As each buffer is filled, it is \'popped\' +-- off, to become a new chunk of the resulting lazy 'L.ByteString'. +-- All this is hidden from the user of the 'Builder'. + +newtype Builder = Builder { + -- Invariant (from Data.ByteString.Lazy): + -- The lists include no null ByteStrings. + runBuilder :: (Buffer -> [S.ByteString]) -> Buffer -> [S.ByteString] + } + +instance Monoid Builder where + mempty = empty + {-# INLINE mempty #-} + mappend = append + {-# INLINE mappend #-} + +------------------------------------------------------------------------ + +-- | /O(1)./ The empty Builder, satisfying +-- +-- * @'toLazyByteString' 'empty' = 'L.empty'@ +-- +empty :: Builder +empty = Builder id +{-# INLINE empty #-} + +-- | /O(1)./ A Builder taking a single byte, satisfying +-- +-- * @'toLazyByteString' ('singleton' b) = 'L.singleton' b@ +-- +singleton :: Word8 -> Builder +singleton = writeN 1 . flip poke +{-# INLINE singleton #-} + +------------------------------------------------------------------------ + +-- | /O(1)./ The concatenation of two Builders, an associative operation +-- with identity 'empty', satisfying +-- +-- * @'toLazyByteString' ('append' x y) = 'L.append' ('toLazyByteString' x) ('toLazyByteString' y)@ +-- +append :: Builder -> Builder -> Builder +append (Builder f) (Builder g) = Builder (f . g) +{-# INLINE append #-} + +-- | /O(1)./ A Builder taking a 'S.ByteString', satisfying +-- +-- * @'toLazyByteString' ('fromByteString' bs) = 'L.fromChunks' [bs]@ +-- +fromByteString :: S.ByteString -> Builder +fromByteString bs + | S.null bs = empty + | otherwise = flush `append` mapBuilder (bs :) +{-# INLINE fromByteString #-} + +-- | /O(1)./ A Builder taking a lazy 'L.ByteString', satisfying +-- +-- * @'toLazyByteString' ('fromLazyByteString' bs) = bs@ +-- +fromLazyByteString :: L.ByteString -> Builder +fromLazyByteString bss = flush `append` mapBuilder (L.toChunks bss ++) +{-# INLINE fromLazyByteString #-} + +------------------------------------------------------------------------ + +-- Our internal buffer type +data Buffer = Buffer {-# UNPACK #-} !(ForeignPtr Word8) + {-# UNPACK #-} !Int -- offset + {-# UNPACK #-} !Int -- used bytes + {-# UNPACK #-} !Int -- length left + +------------------------------------------------------------------------ + +-- | /O(n)./ Extract a lazy 'L.ByteString' from a 'Builder'. +-- The construction work takes place if and when the relevant part of +-- the lazy 'L.ByteString' is demanded. +-- +toLazyByteString :: Builder -> L.ByteString +toLazyByteString m = L.fromChunks $ unsafePerformIO $ do + buf <- newBuffer defaultSize + return (runBuilder (m `append` flush) (const []) buf) + +-- | /O(1)./ Pop the 'S.ByteString' we have constructed so far, if any, +-- yielding a new chunk in the result lazy 'L.ByteString'. +flush :: Builder +flush = Builder $ \ k buf@(Buffer p o u l) -> + if u == 0 + then k buf + else S.PS p o u : k (Buffer p (o+u) 0 l) + +------------------------------------------------------------------------ + +-- +-- copied from Data.ByteString.Lazy +-- +defaultSize :: Int +defaultSize = 32 * k - overhead + where k = 1024 + overhead = 2 * sizeOf (undefined :: Int) + +------------------------------------------------------------------------ + +-- | Sequence an IO operation on the buffer +unsafeLiftIO :: (Buffer -> IO Buffer) -> Builder +unsafeLiftIO f = Builder $ \ k buf -> inlinePerformIO $ do + buf' <- f buf + return (k buf') +{-# INLINE unsafeLiftIO #-} + +-- | Get the size of the buffer +withSize :: (Int -> Builder) -> Builder +withSize f = Builder $ \ k buf@(Buffer _ _ _ l) -> + runBuilder (f l) k buf + +-- | Map the resulting list of bytestrings. +mapBuilder :: ([S.ByteString] -> [S.ByteString]) -> Builder +mapBuilder f = Builder (f .) + +------------------------------------------------------------------------ + +-- | Ensure that there are at least @n@ many bytes available. +ensureFree :: Int -> Builder +ensureFree n = n `seq` withSize $ \ l -> + if n <= l then empty else + flush `append` unsafeLiftIO (const (newBuffer (max n defaultSize))) +{-# INLINE ensureFree #-} + +-- | Ensure that @n@ many bytes are available, and then use @f@ to write some +-- bytes into the memory. +writeN :: Int -> (Ptr Word8 -> IO ()) -> Builder +writeN n f = ensureFree n `append` unsafeLiftIO (writeNBuffer n f) +{-# INLINE writeN #-} + +writeNBuffer :: Int -> (Ptr Word8 -> IO ()) -> Buffer -> IO Buffer +writeNBuffer n f (Buffer fp o u l) = do + withForeignPtr fp (\p -> f (p `plusPtr` (o+u))) + return (Buffer fp o (u+n) (l-n)) +{-# INLINE writeNBuffer #-} + +newBuffer :: Int -> IO Buffer +newBuffer size = do + fp <- S.mallocByteString size + return $! Buffer fp 0 0 size +{-# INLINE newBuffer #-} + +------------------------------------------------------------------------ +-- Aligned, host order writes of storable values + +-- | Ensure that @n@ many bytes are available, and then use @f@ to write some +-- storable values into the memory. +writeNbytes :: Storable a => Int -> (Ptr a -> IO ()) -> Builder +writeNbytes n f = ensureFree n `append` unsafeLiftIO (writeNBufferBytes n f) +{-# INLINE writeNbytes #-} + +writeNBufferBytes :: Storable a => Int -> (Ptr a -> IO ()) -> Buffer -> IO Buffer +writeNBufferBytes n f (Buffer fp o u l) = do + withForeignPtr fp (\p -> f (p `plusPtr` (o+u))) + return (Buffer fp o (u+n) (l-n)) +{-# INLINE writeNBufferBytes #-} + +------------------------------------------------------------------------ + +-- +-- We rely on the fromIntegral to do the right masking for us. +-- The inlining here is critical, and can be worth 4x performance +-- + +-- | Write a Word16 in big endian format +putWord16be :: Word16 -> Builder +putWord16be w = writeN 2 $ \p -> do + poke p (fromIntegral (shiftr_w16 w 8) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (w) :: Word8) +{-# INLINE putWord16be #-} + +-- | Write a Word16 in little endian format +putWord16le :: Word16 -> Builder +putWord16le w = writeN 2 $ \p -> do + poke p (fromIntegral (w) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (shiftr_w16 w 8) :: Word8) +{-# INLINE putWord16le #-} + +-- putWord16le w16 = writeN 2 (\p -> poke (castPtr p) w16) + +-- | Write a Word32 in big endian format +putWord32be :: Word32 -> Builder +putWord32be w = writeN 4 $ \p -> do + poke p (fromIntegral (shiftr_w32 w 24) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w 16) :: Word8) + poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w 8) :: Word8) + poke (p `plusPtr` 3) (fromIntegral (w) :: Word8) +{-# INLINE putWord32be #-} + +-- +-- a data type to tag Put/Check. writes construct these which are then +-- inlined and flattened. matching Checks will be more robust with rules. +-- + +-- | Write a Word32 in little endian format +putWord32le :: Word32 -> Builder +putWord32le w = writeN 4 $ \p -> do + poke p (fromIntegral (w) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w 8) :: Word8) + poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w 16) :: Word8) + poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 w 24) :: Word8) +{-# INLINE putWord32le #-} + +-- on a little endian machine: +-- putWord32le w32 = writeN 4 (\p -> poke (castPtr p) w32) + +-- | Write a Word64 in big endian format +putWord64be :: Word64 -> Builder +#if WORD_SIZE_IN_BITS < 64 +-- +-- To avoid expensive 64 bit shifts on 32 bit machines, we cast to +-- Word32, and write that +-- +putWord64be w = + let a = fromIntegral (shiftr_w64 w 32) :: Word32 + b = fromIntegral w :: Word32 + in writeN 8 $ \p -> do + poke p (fromIntegral (shiftr_w32 a 24) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a 16) :: Word8) + poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a 8) :: Word8) + poke (p `plusPtr` 3) (fromIntegral (a) :: Word8) + poke (p `plusPtr` 4) (fromIntegral (shiftr_w32 b 24) :: Word8) + poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b 16) :: Word8) + poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b 8) :: Word8) + poke (p `plusPtr` 7) (fromIntegral (b) :: Word8) +#else +putWord64be w = writeN 8 $ \p -> do + poke p (fromIntegral (shiftr_w64 w 56) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w 48) :: Word8) + poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 40) :: Word8) + poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 32) :: Word8) + poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 24) :: Word8) + poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 16) :: Word8) + poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w 8) :: Word8) + poke (p `plusPtr` 7) (fromIntegral (w) :: Word8) +#endif +{-# INLINE putWord64be #-} + +-- | Write a Word64 in little endian format +putWord64le :: Word64 -> Builder + +#if WORD_SIZE_IN_BITS < 64 +putWord64le w = + let b = fromIntegral (shiftr_w64 w 32) :: Word32 + a = fromIntegral w :: Word32 + in writeN 8 $ \p -> do + poke (p) (fromIntegral (a) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a 8) :: Word8) + poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a 16) :: Word8) + poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 a 24) :: Word8) + poke (p `plusPtr` 4) (fromIntegral (b) :: Word8) + poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b 8) :: Word8) + poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b 16) :: Word8) + poke (p `plusPtr` 7) (fromIntegral (shiftr_w32 b 24) :: Word8) +#else +putWord64le w = writeN 8 $ \p -> do + poke p (fromIntegral (w) :: Word8) + poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w 8) :: Word8) + poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 16) :: Word8) + poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 24) :: Word8) + poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 32) :: Word8) + poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 40) :: Word8) + poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w 48) :: Word8) + poke (p `plusPtr` 7) (fromIntegral (shiftr_w64 w 56) :: Word8) +#endif +{-# INLINE putWord64le #-} + +-- on a little endian machine: +-- putWord64le w64 = writeN 8 (\p -> poke (castPtr p) w64) + +------------------------------------------------------------------------ +-- Unaligned, word size ops + +-- | /O(1)./ A Builder taking a single native machine word. The word is +-- written in host order, host endian form, for the machine you're on. +-- On a 64 bit machine the Word is an 8 byte value, on a 32 bit machine, +-- 4 bytes. Values written this way are not portable to +-- different endian or word sized machines, without conversion. +-- +putWordhost :: Word -> Builder +putWordhost w = writeNbytes (sizeOf (undefined :: Word)) (\p -> poke p w) +{-# INLINE putWordhost #-} + +-- | Write a Word16 in native host order and host endianness. +-- 2 bytes will be written, unaligned. +putWord16host :: Word16 -> Builder +putWord16host w16 = writeNbytes (sizeOf (undefined :: Word16)) (\p -> poke p w16) +{-# INLINE putWord16host #-} + +-- | Write a Word32 in native host order and host endianness. +-- 4 bytes will be written, unaligned. +putWord32host :: Word32 -> Builder +putWord32host w32 = writeNbytes (sizeOf (undefined :: Word32)) (\p -> poke p w32) +{-# INLINE putWord32host #-} + +-- | Write a Word64 in native host order. +-- On a 32 bit machine we write two host order Word32s, in big endian form. +-- 8 bytes will be written, unaligned. +putWord64host :: Word64 -> Builder +putWord64host w = writeNbytes (sizeOf (undefined :: Word64)) (\p -> poke p w) +{-# INLINE putWord64host #-} + +------------------------------------------------------------------------ +-- Unchecked shifts + +{-# INLINE shiftr_w16 #-} +shiftr_w16 :: Word16 -> Int -> Word16 +{-# INLINE shiftr_w32 #-} +shiftr_w32 :: Word32 -> Int -> Word32 +{-# INLINE shiftr_w64 #-} +shiftr_w64 :: Word64 -> Int -> Word64 + +#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) +shiftr_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftRL#` i) +shiftr_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftRL#` i) + +#if WORD_SIZE_IN_BITS < 64 +shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL64#` i) + +#if __GLASGOW_HASKELL__ <= 606 +-- Exported by GHC.Word in GHC 6.8 and higher +foreign import ccall unsafe "stg_uncheckedShiftRL64" + uncheckedShiftRL64# :: Word64# -> Int# -> Word64# +#endif + +#else +shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL#` i) +#endif + +#else +shiftr_w16 = shiftR +shiftr_w32 = shiftR +shiftr_w64 = shiftR +#endif diff --git a/src/runtime/haskell/Data/Binary/Get.hs b/src/runtime/haskell/Data/Binary/Get.hs new file mode 100644 index 000000000..51062ad31 --- /dev/null +++ b/src/runtime/haskell/Data/Binary/Get.hs @@ -0,0 +1,544 @@ +{-# LANGUAGE CPP #-} +{-# OPTIONS_GHC -fglasgow-exts #-} +-- for unboxed shifts + +----------------------------------------------------------------------------- +-- | +-- Module : Data.Binary.Get +-- Copyright : Lennart Kolmodin +-- License : BSD3-style (see LICENSE) +-- +-- Maintainer : Lennart Kolmodin <kolmodin@dtek.chalmers.se> +-- Stability : experimental +-- Portability : portable to Hugs and GHC. +-- +-- The Get monad. A monad for efficiently building structures from +-- encoded lazy ByteStrings +-- +----------------------------------------------------------------------------- + +#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) +#include "MachDeps.h" +#endif + +module Data.Binary.Get ( + + -- * The Get type + Get + , runGet + , runGetState + + -- * Parsing + , skip + , uncheckedSkip + , lookAhead + , lookAheadM + , lookAheadE + , uncheckedLookAhead + + -- * Utility + , bytesRead + , getBytes + , remaining + , isEmpty + + -- * Parsing particular types + , getWord8 + + -- ** ByteStrings + , getByteString + , getLazyByteString + , getLazyByteStringNul + , getRemainingLazyByteString + + -- ** Big-endian reads + , getWord16be + , getWord32be + , getWord64be + + -- ** Little-endian reads + , getWord16le + , getWord32le + , getWord64le + + -- ** Host-endian, unaligned reads + , getWordhost + , getWord16host + , getWord32host + , getWord64host + + ) where + +import Control.Monad (when,liftM,ap) +import Control.Monad.Fix +import Data.Maybe (isNothing) + +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as L + +#ifdef BYTESTRING_IN_BASE +import qualified Data.ByteString.Base as B +#else +import qualified Data.ByteString.Internal as B +import qualified Data.ByteString.Lazy.Internal as L +#endif + +#ifdef APPLICATIVE_IN_BASE +import Control.Applicative (Applicative(..)) +#endif + +import Foreign + +-- used by splitAtST +import Control.Monad.ST +import Data.STRef + +#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) +import GHC.Base +import GHC.Word +import GHC.Int +#endif + +-- | The parse state +data S = S {-# UNPACK #-} !B.ByteString -- current chunk + L.ByteString -- the rest of the input + {-# UNPACK #-} !Int64 -- bytes read + +-- | The Get monad is just a State monad carrying around the input ByteString +newtype Get a = Get { unGet :: S -> (a, S) } + +instance Functor Get where + fmap f m = Get (\s -> case unGet m s of + (a, s') -> (f a, s')) + {-# INLINE fmap #-} + +#ifdef APPLICATIVE_IN_BASE +instance Applicative Get where + pure = return + (<*>) = ap +#endif + +instance Monad Get where + return a = Get (\s -> (a, s)) + {-# INLINE return #-} + + m >>= k = Get (\s -> case unGet m s of + (a, s') -> unGet (k a) s') + {-# INLINE (>>=) #-} + + fail = failDesc + +instance MonadFix Get where + mfix f = Get (\s -> let (a,s') = unGet (f a) s + in (a,s')) + +------------------------------------------------------------------------ + +get :: Get S +get = Get (\s -> (s, s)) + +put :: S -> Get () +put s = Get (\_ -> ((), s)) + +------------------------------------------------------------------------ +-- +-- dons, GHC 6.10: explicit inlining disabled, was killing performance. +-- Without it, GHC seems to do just fine. And we get similar +-- performance with 6.8.2 anyway. +-- + +initState :: L.ByteString -> S +initState xs = mkState xs 0 +{- INLINE initState -} + +{- +initState (B.LPS xs) = + case xs of + [] -> S B.empty L.empty 0 + (x:xs') -> S x (B.LPS xs') 0 +-} + +#ifndef BYTESTRING_IN_BASE +mkState :: L.ByteString -> Int64 -> S +mkState l = case l of + L.Empty -> S B.empty L.empty + L.Chunk x xs -> S x xs +{- INLINE mkState -} + +#else +mkState :: L.ByteString -> Int64 -> S +mkState (B.LPS xs) = + case xs of + [] -> S B.empty L.empty + (x:xs') -> S x (B.LPS xs') +#endif + +-- | Run the Get monad applies a 'get'-based parser on the input ByteString +runGet :: Get a -> L.ByteString -> a +runGet m str = case unGet m (initState str) of (a, _) -> a + +-- | Run the Get monad applies a 'get'-based parser on the input +-- ByteString. Additional to the result of get it returns the number of +-- consumed bytes and the rest of the input. +runGetState :: Get a -> L.ByteString -> Int64 -> (a, L.ByteString, Int64) +runGetState m str off = + case unGet m (mkState str off) of + (a, ~(S s ss newOff)) -> (a, s `join` ss, newOff) + +------------------------------------------------------------------------ + +failDesc :: String -> Get a +failDesc err = do + S _ _ bytes <- get + Get (error (err ++ ". Failed reading at byte position " ++ show bytes)) + +-- | Skip ahead @n@ bytes. Fails if fewer than @n@ bytes are available. +skip :: Int -> Get () +skip n = readN (fromIntegral n) (const ()) + +-- | Skip ahead @n@ bytes. No error if there isn't enough bytes. +uncheckedSkip :: Int64 -> Get () +uncheckedSkip n = do + S s ss bytes <- get + if fromIntegral (B.length s) >= n + then put (S (B.drop (fromIntegral n) s) ss (bytes + n)) + else do + let rest = L.drop (n - fromIntegral (B.length s)) ss + put $! mkState rest (bytes + n) + +-- | Run @ga@, but return without consuming its input. +-- Fails if @ga@ fails. +lookAhead :: Get a -> Get a +lookAhead ga = do + s <- get + a <- ga + put s + return a + +-- | Like 'lookAhead', but consume the input if @gma@ returns 'Just _'. +-- Fails if @gma@ fails. +lookAheadM :: Get (Maybe a) -> Get (Maybe a) +lookAheadM gma = do + s <- get + ma <- gma + when (isNothing ma) $ + put s + return ma + +-- | Like 'lookAhead', but consume the input if @gea@ returns 'Right _'. +-- Fails if @gea@ fails. +lookAheadE :: Get (Either a b) -> Get (Either a b) +lookAheadE gea = do + s <- get + ea <- gea + case ea of + Left _ -> put s + _ -> return () + return ea + +-- | Get the next up to @n@ bytes as a lazy ByteString, without consuming them. +uncheckedLookAhead :: Int64 -> Get L.ByteString +uncheckedLookAhead n = do + S s ss _ <- get + if n <= fromIntegral (B.length s) + then return (L.fromChunks [B.take (fromIntegral n) s]) + else return $ L.take n (s `join` ss) + +------------------------------------------------------------------------ +-- Utility + +-- | Get the total number of bytes read to this point. +bytesRead :: Get Int64 +bytesRead = do + S _ _ b <- get + return b + +-- | Get the number of remaining unparsed bytes. +-- Useful for checking whether all input has been consumed. +-- Note that this forces the rest of the input. +remaining :: Get Int64 +remaining = do + S s ss _ <- get + return (fromIntegral (B.length s) + L.length ss) + +-- | Test whether all input has been consumed, +-- i.e. there are no remaining unparsed bytes. +isEmpty :: Get Bool +isEmpty = do + S s ss _ <- get + return (B.null s && L.null ss) + +------------------------------------------------------------------------ +-- Utility with ByteStrings + +-- | An efficient 'get' method for strict ByteStrings. Fails if fewer +-- than @n@ bytes are left in the input. +getByteString :: Int -> Get B.ByteString +getByteString n = readN n id +{-# INLINE getByteString #-} + +-- | An efficient 'get' method for lazy ByteStrings. Does not fail if fewer than +-- @n@ bytes are left in the input. +getLazyByteString :: Int64 -> Get L.ByteString +getLazyByteString n = do + S s ss bytes <- get + let big = s `join` ss + case splitAtST n big of + (consume, rest) -> do put $ mkState rest (bytes + n) + return consume +{-# INLINE getLazyByteString #-} + +-- | Get a lazy ByteString that is terminated with a NUL byte. Fails +-- if it reaches the end of input without hitting a NUL. +getLazyByteStringNul :: Get L.ByteString +getLazyByteStringNul = do + S s ss bytes <- get + let big = s `join` ss + (consume, t) = L.break (== 0) big + (h, rest) = L.splitAt 1 t + if L.null h + then fail "too few bytes" + else do + put $ mkState rest (bytes + L.length consume + 1) + return consume +{-# INLINE getLazyByteStringNul #-} + +-- | Get the remaining bytes as a lazy ByteString +getRemainingLazyByteString :: Get L.ByteString +getRemainingLazyByteString = do + S s ss _ <- get + return (s `join` ss) + +------------------------------------------------------------------------ +-- Helpers + +-- | Pull @n@ bytes from the input, as a strict ByteString. +getBytes :: Int -> Get B.ByteString +getBytes n = do + S s ss bytes <- get + if n <= B.length s + then do let (consume,rest) = B.splitAt n s + put $! S rest ss (bytes + fromIntegral n) + return $! consume + else + case L.splitAt (fromIntegral n) (s `join` ss) of + (consuming, rest) -> + do let now = B.concat . L.toChunks $ consuming + put $! mkState rest (bytes + fromIntegral n) + -- forces the next chunk before this one is returned + if (B.length now < n) + then + fail "too few bytes" + else + return now +{- INLINE getBytes -} +-- ^ important + +#ifndef BYTESTRING_IN_BASE +join :: B.ByteString -> L.ByteString -> L.ByteString +join bb lb + | B.null bb = lb + | otherwise = L.Chunk bb lb + +#else +join :: B.ByteString -> L.ByteString -> L.ByteString +join bb (B.LPS lb) + | B.null bb = B.LPS lb + | otherwise = B.LPS (bb:lb) +#endif + -- don't use L.append, it's strict in it's second argument :/ +{- INLINE join -} + +-- | Split a ByteString. If the first result is consumed before the -- +-- second, this runs in constant heap space. +-- +-- You must force the returned tuple for that to work, e.g. +-- +-- > case splitAtST n xs of +-- > (ys,zs) -> consume ys ... consume zs +-- +splitAtST :: Int64 -> L.ByteString -> (L.ByteString, L.ByteString) +splitAtST i ps | i <= 0 = (L.empty, ps) +#ifndef BYTESTRING_IN_BASE +splitAtST i ps = runST ( + do r <- newSTRef undefined + xs <- first r i ps + ys <- unsafeInterleaveST (readSTRef r) + return (xs, ys)) + + where + first r 0 xs@(L.Chunk _ _) = writeSTRef r xs >> return L.Empty + first r _ L.Empty = writeSTRef r L.Empty >> return L.Empty + + first r n (L.Chunk x xs) + | n < l = do writeSTRef r (L.Chunk (B.drop (fromIntegral n) x) xs) + return $ L.Chunk (B.take (fromIntegral n) x) L.Empty + | otherwise = do writeSTRef r (L.drop (n - l) xs) + liftM (L.Chunk x) $ unsafeInterleaveST (first r (n - l) xs) + + where l = fromIntegral (B.length x) +#else +splitAtST i (B.LPS ps) = runST ( + do r <- newSTRef undefined + xs <- first r i ps + ys <- unsafeInterleaveST (readSTRef r) + return (B.LPS xs, B.LPS ys)) + + where first r 0 xs = writeSTRef r xs >> return [] + first r _ [] = writeSTRef r [] >> return [] + first r n (x:xs) + | n < l = do writeSTRef r (B.drop (fromIntegral n) x : xs) + return [B.take (fromIntegral n) x] + | otherwise = do writeSTRef r (L.toChunks (L.drop (n - l) (B.LPS xs))) + fmap (x:) $ unsafeInterleaveST (first r (n - l) xs) + + where l = fromIntegral (B.length x) +#endif +{- INLINE splitAtST -} + +-- Pull n bytes from the input, and apply a parser to those bytes, +-- yielding a value. If less than @n@ bytes are available, fail with an +-- error. This wraps @getBytes@. +readN :: Int -> (B.ByteString -> a) -> Get a +readN n f = fmap f $ getBytes n +{- INLINE readN -} +-- ^ important + +------------------------------------------------------------------------ +-- Primtives + +-- helper, get a raw Ptr onto a strict ByteString copied out of the +-- underlying lazy byteString. So many indirections from the raw parser +-- state that my head hurts... + +getPtr :: Storable a => Int -> Get a +getPtr n = do + (fp,o,_) <- readN n B.toForeignPtr + return . B.inlinePerformIO $ withForeignPtr fp $ \p -> peek (castPtr $ p `plusPtr` o) +{- INLINE getPtr -} + +------------------------------------------------------------------------ + +-- | Read a Word8 from the monad state +getWord8 :: Get Word8 +getWord8 = getPtr (sizeOf (undefined :: Word8)) +{- INLINE getWord8 -} + +-- | Read a Word16 in big endian format +getWord16be :: Get Word16 +getWord16be = do + s <- readN 2 id + return $! (fromIntegral (s `B.index` 0) `shiftl_w16` 8) .|. + (fromIntegral (s `B.index` 1)) +{- INLINE getWord16be -} + +-- | Read a Word16 in little endian format +getWord16le :: Get Word16 +getWord16le = do + s <- readN 2 id + return $! (fromIntegral (s `B.index` 1) `shiftl_w16` 8) .|. + (fromIntegral (s `B.index` 0) ) +{- INLINE getWord16le -} + +-- | Read a Word32 in big endian format +getWord32be :: Get Word32 +getWord32be = do + s <- readN 4 id + return $! (fromIntegral (s `B.index` 0) `shiftl_w32` 24) .|. + (fromIntegral (s `B.index` 1) `shiftl_w32` 16) .|. + (fromIntegral (s `B.index` 2) `shiftl_w32` 8) .|. + (fromIntegral (s `B.index` 3) ) +{- INLINE getWord32be -} + +-- | Read a Word32 in little endian format +getWord32le :: Get Word32 +getWord32le = do + s <- readN 4 id + return $! (fromIntegral (s `B.index` 3) `shiftl_w32` 24) .|. + (fromIntegral (s `B.index` 2) `shiftl_w32` 16) .|. + (fromIntegral (s `B.index` 1) `shiftl_w32` 8) .|. + (fromIntegral (s `B.index` 0) ) +{- INLINE getWord32le -} + +-- | Read a Word64 in big endian format +getWord64be :: Get Word64 +getWord64be = do + s <- readN 8 id + return $! (fromIntegral (s `B.index` 0) `shiftl_w64` 56) .|. + (fromIntegral (s `B.index` 1) `shiftl_w64` 48) .|. + (fromIntegral (s `B.index` 2) `shiftl_w64` 40) .|. + (fromIntegral (s `B.index` 3) `shiftl_w64` 32) .|. + (fromIntegral (s `B.index` 4) `shiftl_w64` 24) .|. + (fromIntegral (s `B.index` 5) `shiftl_w64` 16) .|. + (fromIntegral (s `B.index` 6) `shiftl_w64` 8) .|. + (fromIntegral (s `B.index` 7) ) +{- INLINE getWord64be -} + +-- | Read a Word64 in little endian format +getWord64le :: Get Word64 +getWord64le = do + s <- readN 8 id + return $! (fromIntegral (s `B.index` 7) `shiftl_w64` 56) .|. + (fromIntegral (s `B.index` 6) `shiftl_w64` 48) .|. + (fromIntegral (s `B.index` 5) `shiftl_w64` 40) .|. + (fromIntegral (s `B.index` 4) `shiftl_w64` 32) .|. + (fromIntegral (s `B.index` 3) `shiftl_w64` 24) .|. + (fromIntegral (s `B.index` 2) `shiftl_w64` 16) .|. + (fromIntegral (s `B.index` 1) `shiftl_w64` 8) .|. + (fromIntegral (s `B.index` 0) ) +{- INLINE getWord64le -} + +------------------------------------------------------------------------ +-- Host-endian reads + +-- | /O(1)./ Read a single native machine word. The word is read in +-- host order, host endian form, for the machine you're on. On a 64 bit +-- machine the Word is an 8 byte value, on a 32 bit machine, 4 bytes. +getWordhost :: Get Word +getWordhost = getPtr (sizeOf (undefined :: Word)) +{- INLINE getWordhost -} + +-- | /O(1)./ Read a 2 byte Word16 in native host order and host endianness. +getWord16host :: Get Word16 +getWord16host = getPtr (sizeOf (undefined :: Word16)) +{- INLINE getWord16host -} + +-- | /O(1)./ Read a Word32 in native host order and host endianness. +getWord32host :: Get Word32 +getWord32host = getPtr (sizeOf (undefined :: Word32)) +{- INLINE getWord32host -} + +-- | /O(1)./ Read a Word64 in native host order and host endianess. +getWord64host :: Get Word64 +getWord64host = getPtr (sizeOf (undefined :: Word64)) +{- INLINE getWord64host -} + +------------------------------------------------------------------------ +-- Unchecked shifts + +shiftl_w16 :: Word16 -> Int -> Word16 +shiftl_w32 :: Word32 -> Int -> Word32 +shiftl_w64 :: Word64 -> Int -> Word64 + +#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) +shiftl_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftL#` i) +shiftl_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftL#` i) + +#if WORD_SIZE_IN_BITS < 64 +shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL64#` i) + +#if __GLASGOW_HASKELL__ <= 606 +-- Exported by GHC.Word in GHC 6.8 and higher +foreign import ccall unsafe "stg_uncheckedShiftL64" + uncheckedShiftL64# :: Word64# -> Int# -> Word64# +#endif + +#else +shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL#` i) +#endif + +#else +shiftl_w16 = shiftL +shiftl_w32 = shiftL +shiftl_w64 = shiftL +#endif diff --git a/src/runtime/haskell/Data/Binary/Put.hs b/src/runtime/haskell/Data/Binary/Put.hs new file mode 100644 index 000000000..a1f78dfba --- /dev/null +++ b/src/runtime/haskell/Data/Binary/Put.hs @@ -0,0 +1,216 @@ +{-# LANGUAGE CPP #-} +----------------------------------------------------------------------------- +-- | +-- Module : Data.Binary.Put +-- Copyright : Lennart Kolmodin +-- License : BSD3-style (see LICENSE) +-- +-- Maintainer : Lennart Kolmodin <kolmodin@dtek.chalmers.se> +-- Stability : stable +-- Portability : Portable to Hugs and GHC. Requires MPTCs +-- +-- The Put monad. A monad for efficiently constructing lazy bytestrings. +-- +----------------------------------------------------------------------------- + +module Data.Binary.Put ( + + -- * The Put type + Put + , PutM(..) + , runPut + , runPutM + , putBuilder + , execPut + + -- * Flushing the implicit parse state + , flush + + -- * Primitives + , putWord8 + , putByteString + , putLazyByteString + + -- * Big-endian primitives + , putWord16be + , putWord32be + , putWord64be + + -- * Little-endian primitives + , putWord16le + , putWord32le + , putWord64le + + -- * Host-endian, unaligned writes + , putWordhost -- :: Word -> Put + , putWord16host -- :: Word16 -> Put + , putWord32host -- :: Word32 -> Put + , putWord64host -- :: Word64 -> Put + + ) where + +import Data.Monoid +import Data.Binary.Builder (Builder, toLazyByteString) +import qualified Data.Binary.Builder as B + +import Data.Word +import qualified Data.ByteString as S +import qualified Data.ByteString.Lazy as L + +#ifdef APPLICATIVE_IN_BASE +import Control.Applicative +#endif + + +------------------------------------------------------------------------ + +-- XXX Strict in buffer only. +data PairS a = PairS a {-# UNPACK #-}!Builder + +sndS :: PairS a -> Builder +sndS (PairS _ b) = b + +-- | The PutM type. A Writer monad over the efficient Builder monoid. +newtype PutM a = Put { unPut :: PairS a } + +-- | Put merely lifts Builder into a Writer monad, applied to (). +type Put = PutM () + +instance Functor PutM where + fmap f m = Put $ let PairS a w = unPut m in PairS (f a) w + {-# INLINE fmap #-} + +#ifdef APPLICATIVE_IN_BASE +instance Applicative PutM where + pure = return + m <*> k = Put $ + let PairS f w = unPut m + PairS x w' = unPut k + in PairS (f x) (w `mappend` w') +#endif + +-- Standard Writer monad, with aggressive inlining +instance Monad PutM where + return a = Put $ PairS a mempty + {-# INLINE return #-} + + m >>= k = Put $ + let PairS a w = unPut m + PairS b w' = unPut (k a) + in PairS b (w `mappend` w') + {-# INLINE (>>=) #-} + + m >> k = Put $ + let PairS _ w = unPut m + PairS b w' = unPut k + in PairS b (w `mappend` w') + {-# INLINE (>>) #-} + +tell :: Builder -> Put +tell b = Put $ PairS () b +{-# INLINE tell #-} + +putBuilder :: Builder -> Put +putBuilder = tell +{-# INLINE putBuilder #-} + +-- | Run the 'Put' monad +execPut :: PutM a -> Builder +execPut = sndS . unPut +{-# INLINE execPut #-} + +-- | Run the 'Put' monad with a serialiser +runPut :: Put -> L.ByteString +runPut = toLazyByteString . sndS . unPut +{-# INLINE runPut #-} + +-- | Run the 'Put' monad with a serialiser and get its result +runPutM :: PutM a -> (a, L.ByteString) +runPutM (Put (PairS f s)) = (f, toLazyByteString s) +{-# INLINE runPutM #-} + +------------------------------------------------------------------------ + +-- | Pop the ByteString we have constructed so far, if any, yielding a +-- new chunk in the result ByteString. +flush :: Put +flush = tell B.flush +{-# INLINE flush #-} + +-- | Efficiently write a byte into the output buffer +putWord8 :: Word8 -> Put +putWord8 = tell . B.singleton +{-# INLINE putWord8 #-} + +-- | An efficient primitive to write a strict ByteString into the output buffer. +-- It flushes the current buffer, and writes the argument into a new chunk. +putByteString :: S.ByteString -> Put +putByteString = tell . B.fromByteString +{-# INLINE putByteString #-} + +-- | Write a lazy ByteString efficiently, simply appending the lazy +-- ByteString chunks to the output buffer +putLazyByteString :: L.ByteString -> Put +putLazyByteString = tell . B.fromLazyByteString +{-# INLINE putLazyByteString #-} + +-- | Write a Word16 in big endian format +putWord16be :: Word16 -> Put +putWord16be = tell . B.putWord16be +{-# INLINE putWord16be #-} + +-- | Write a Word16 in little endian format +putWord16le :: Word16 -> Put +putWord16le = tell . B.putWord16le +{-# INLINE putWord16le #-} + +-- | Write a Word32 in big endian format +putWord32be :: Word32 -> Put +putWord32be = tell . B.putWord32be +{-# INLINE putWord32be #-} + +-- | Write a Word32 in little endian format +putWord32le :: Word32 -> Put +putWord32le = tell . B.putWord32le +{-# INLINE putWord32le #-} + +-- | Write a Word64 in big endian format +putWord64be :: Word64 -> Put +putWord64be = tell . B.putWord64be +{-# INLINE putWord64be #-} + +-- | Write a Word64 in little endian format +putWord64le :: Word64 -> Put +putWord64le = tell . B.putWord64le +{-# INLINE putWord64le #-} + +------------------------------------------------------------------------ + +-- | /O(1)./ Write a single native machine word. The word is +-- written in host order, host endian form, for the machine you're on. +-- On a 64 bit machine the Word is an 8 byte value, on a 32 bit machine, +-- 4 bytes. Values written this way are not portable to +-- different endian or word sized machines, without conversion. +-- +putWordhost :: Word -> Put +putWordhost = tell . B.putWordhost +{-# INLINE putWordhost #-} + +-- | /O(1)./ Write a Word16 in native host order and host endianness. +-- For portability issues see @putWordhost@. +putWord16host :: Word16 -> Put +putWord16host = tell . B.putWord16host +{-# INLINE putWord16host #-} + +-- | /O(1)./ Write a Word32 in native host order and host endianness. +-- For portability issues see @putWordhost@. +putWord32host :: Word32 -> Put +putWord32host = tell . B.putWord32host +{-# INLINE putWord32host #-} + +-- | /O(1)./ Write a Word64 in native host order +-- On a 32 bit machine we write two host order Word32s, in big endian form. +-- For portability issues see @putWordhost@. +putWord64host :: Word64 -> Put +putWord64host = tell . B.putWord64host +{-# INLINE putWord64host #-} diff --git a/src/runtime/haskell/PGF.hs b/src/runtime/haskell/PGF.hs new file mode 100644 index 000000000..6c192095d --- /dev/null +++ b/src/runtime/haskell/PGF.hs @@ -0,0 +1,352 @@ +------------------------------------------------- +-- | +-- Module : PGF +-- Maintainer : Aarne Ranta +-- Stability : stable +-- Portability : portable +-- +-- This module is an Application Programming Interface to +-- load and interpret grammars compiled in Portable Grammar Format (PGF). +-- The PGF format is produced as a final output from the GF compiler. +-- The API is meant to be used for embedding GF grammars in Haskell +-- programs +------------------------------------------------- + +module PGF( + -- * PGF + PGF, + readPGF, + + -- * Identifiers + CId, mkCId, wildCId, + showCId, readCId, + + -- * Languages + Language, + showLanguage, readLanguage, + languages, abstractName, languageCode, + + -- * Types + Type, Hypo, + showType, readType, + mkType, mkHypo, mkDepHypo, mkImplHypo, + categories, startCat, + + -- * Functions + functions, functionType, + + -- * Expressions & Trees + -- ** Tree + Tree, + + -- ** Expr + Expr, + showExpr, readExpr, + mkApp, unApp, + mkStr, unStr, + mkInt, unInt, + mkDouble, unDouble, + mkMeta, isMeta, + + -- * Operations + -- ** Linearization + linearize, linearizeAllLang, linearizeAll, + showPrintName, + + -- ** Parsing + parse, parseWithRecovery, canParse, parseAllLang, parseAll, + + -- ** Evaluation + PGF.compute, paraphrase, + + -- ** Type Checking + -- | The type checker in PGF does both type checking and renaming + -- i.e. it verifies that all identifiers are declared and it + -- distinguishes between global function or type indentifiers and + -- variable names. The type checker should always be applied on + -- expressions entered by the user i.e. those produced via functions + -- like 'readType' and 'readExpr' because otherwise unexpected results + -- could appear. All typechecking functions returns updated versions + -- of the input types or expressions because the typechecking could + -- also lead to metavariables instantiations. + checkType, checkExpr, inferExpr, + TcError(..), ppTcError, + + -- ** Word Completion (Incremental Parsing) + complete, + Incremental.ParseState, + Incremental.initState, Incremental.nextState, Incremental.getCompletions, Incremental.recoveryStates, Incremental.extractTrees, + + -- ** Generation + generateRandom, generateAll, generateAllDepth, + + -- ** Morphological Analysis + Lemma, Analysis, Morpho, + lookupMorpho, buildMorpho, + + -- ** Visualizations + graphvizAbstractTree, + graphvizParseTree, + graphvizDependencyTree, + graphvizAlignment, + + -- * Browsing + browse + ) where + +import PGF.CId +import PGF.Linearize +import PGF.Generate +import PGF.TypeCheck +import PGF.Paraphrase +import PGF.VisualizeTree +import PGF.Macros +import PGF.Expr (Tree) +import PGF.Morphology +import PGF.Data hiding (functions) +import PGF.Binary +import qualified PGF.Parsing.FCFG.Active as Active +import qualified PGF.Parsing.FCFG.Incremental as Incremental +import qualified GF.Compile.GeneratePMCFG as PMCFG + +import GF.Infra.Option +import GF.Data.Utilities (replace) + +import Data.Char +import qualified Data.Map as Map +import qualified Data.IntMap as IntMap +import Data.Maybe +import Data.Binary +import Data.List(mapAccumL) +import System.Random (newStdGen) +import Control.Monad +import Text.PrettyPrint + +--------------------------------------------------- +-- Interface +--------------------------------------------------- + +-- | Reads file in Portable Grammar Format and produces +-- 'PGF' structure. The file is usually produced with: +-- +-- > $ gf -make <grammar file name> +readPGF :: FilePath -> IO PGF + +-- | Linearizes given expression as string in the language +linearize :: PGF -> Language -> Tree -> String + +-- | Tries to parse the given string in the specified language +-- and to produce abstract syntax expression. An empty +-- list is returned if the parsing is not successful. The list may also +-- contain more than one element if the grammar is ambiguous. +-- Throws an exception if the given language cannot be used +-- for parsing, see 'canParse'. +parse :: PGF -> Language -> Type -> String -> [Tree] + +parseWithRecovery :: PGF -> Language -> Type -> [Type] -> String -> [Tree] + +-- | Checks whether the given language can be used for parsing. +canParse :: PGF -> Language -> Bool + +-- | The same as 'linearizeAllLang' but does not return +-- the language. +linearizeAll :: PGF -> Tree -> [String] + +-- | Linearizes given expression as string in all languages +-- available in the grammar. +linearizeAllLang :: PGF -> Tree -> [(Language,String)] + +-- | Show the printname of a type +showPrintName :: PGF -> Language -> Type -> String + +-- | The same as 'parseAllLang' but does not return +-- the language. +parseAll :: PGF -> Type -> String -> [[Tree]] + +-- | Tries to parse the given string with all available languages. +-- Languages which cannot be used for parsing (see 'canParse') +-- are ignored. +-- The returned list contains pairs of language +-- and list of abstract syntax expressions +-- (this is a list, since grammars can be ambiguous). +-- Only those languages +-- for which at least one parsing is possible are listed. +parseAllLang :: PGF -> Type -> String -> [(Language,[Tree])] + +-- | The same as 'generateAllDepth' but does not limit +-- the depth in the generation. +generateAll :: PGF -> Type -> [Expr] + +-- | Generates an infinite list of random abstract syntax expressions. +-- This is usefull for tree bank generation which after that can be used +-- for grammar testing. +generateRandom :: PGF -> Type -> IO [Expr] + +-- | Generates an exhaustive possibly infinite list of +-- abstract syntax expressions. A depth can be specified +-- to limit the search space. +generateAllDepth :: PGF -> Type -> Maybe Int -> [Expr] + +-- | List of all languages available in the given grammar. +languages :: PGF -> [Language] + +-- | Gets the RFC 4646 language tag +-- of the language which the given concrete syntax implements, +-- if this is listed in the source grammar. +-- Example language tags include @\"en\"@ for English, +-- and @\"en-UK\"@ for British English. +languageCode :: PGF -> Language -> Maybe String + +-- | The abstract language name is the name of the top-level +-- abstract module +abstractName :: PGF -> Language + +-- | List of all categories defined in the given grammar. +-- The categories are defined in the abstract syntax +-- with the \'cat\' keyword. +categories :: PGF -> [CId] + +-- | The start category is defined in the grammar with +-- the \'startcat\' flag. This is usually the sentence category +-- but it is not necessary. Despite that there is a start category +-- defined you can parse with any category. The start category +-- definition is just for convenience. +startCat :: PGF -> Type + +-- | List of all functions defined in the abstract syntax +functions :: PGF -> [CId] + +-- | The type of a given function +functionType :: PGF -> CId -> Maybe Type + +-- | Complete the last word in the given string. If the input +-- is empty or ends in whitespace, the last word is considred +-- to be the empty string. This means that the completions +-- will be all possible next words. +complete :: PGF -> Language -> Type -> String + -> [String] -- ^ Possible completions, + -- including the given input. + + +--------------------------------------------------- +-- Implementation +--------------------------------------------------- + +readPGF f = decodeFile f >>= addParsers + +-- Adds parsers for all concretes that don't have a parser and that have parser=ondemand. +addParsers :: PGF -> IO PGF +addParsers pgf = do cncs <- sequence [if wantsParser cnc then addParser lang cnc else return (lang,cnc) + | (lang,cnc) <- Map.toList (concretes pgf)] + return pgf { concretes = Map.fromList cncs } + where + wantsParser cnc = isNothing (parser cnc) && Map.lookup (mkCId "parser") (cflags cnc) == Just "ondemand" + addParser lang cnc = do pinfo <- PMCFG.convertConcrete noOptions (abstract pgf) lang cnc + return (lang,cnc { parser = Just pinfo }) + +linearize pgf lang = concat . take 1 . PGF.Linearize.linearizes pgf lang + +parse pgf lang typ s = + case Map.lookup lang (concretes pgf) of + Just cnc -> case parser cnc of + Just pinfo -> if Map.lookup (mkCId "erasing") (cflags cnc) == Just "on" + then Incremental.parse pgf lang typ (words s) + else Active.parse "t" pinfo typ (words s) + Nothing -> error ("No parser built for language: " ++ showCId lang) + Nothing -> error ("Unknown language: " ++ showCId lang) + +parseWithRecovery pgf lang typ open_typs s = Incremental.parseWithRecovery pgf lang typ open_typs (words s) + +canParse pgf cnc = isJust (lookParser pgf cnc) + +linearizeAll mgr = map snd . linearizeAllLang mgr +linearizeAllLang mgr t = + [(lang,PGF.linearize mgr lang t) | lang <- languages mgr] + +showPrintName pgf lang (DTyp _ c _) = realize $ lookPrintName pgf lang c + +parseAll mgr typ = map snd . parseAllLang mgr typ + +parseAllLang mgr typ s = + [(lang,ts) | lang <- languages mgr, canParse mgr lang, let ts = parse mgr lang typ s, not (null ts)] + +generateRandom pgf cat = do + gen <- newStdGen + return $ genRandom gen pgf cat + +generateAll pgf cat = generate pgf cat Nothing +generateAllDepth pgf cat = generate pgf cat + +abstractName pgf = absname pgf + +languages pgf = cncnames pgf + +languageCode pgf lang = + fmap (replace '_' '-') $ lookConcrFlag pgf lang (mkCId "language") + +categories pgf = [c | (c,hs) <- Map.toList (cats (abstract pgf))] + +startCat pgf = DTyp [] (lookStartCat pgf) [] + +functions pgf = Map.keys (funs (abstract pgf)) + +functionType pgf fun = + case Map.lookup fun (funs (abstract pgf)) of + Just (ty,_,_) -> Just ty + Nothing -> Nothing + +complete pgf from typ input = + let (ws,prefix) = tokensAndPrefix input + state0 = Incremental.initState pgf from typ + in case loop state0 ws of + Nothing -> [] + Just state -> + (if null prefix && not (null (Incremental.extractTrees state typ)) then [unwords ws ++ " "] else []) + ++ [unwords (ws++[c]) ++ " " | c <- Map.keys (Incremental.getCompletions state prefix)] + where + tokensAndPrefix :: String -> ([String],String) + tokensAndPrefix s | not (null s) && isSpace (last s) = (ws, "") + | null ws = ([],"") + | otherwise = (init ws, last ws) + where ws = words s + + loop ps [] = Just ps + loop ps (t:ts) = case Incremental.nextState ps t of + Left es -> Nothing + Right ps -> loop ps ts + +-- | Converts an expression to normal form +compute :: PGF -> Expr -> Expr +compute pgf = PGF.Data.normalForm (funs (abstract pgf)) 0 [] + +browse :: PGF -> CId -> Maybe (String,[CId],[CId]) +browse pgf id = fmap (\def -> (def,producers,consumers)) definition + where + definition = case Map.lookup id (funs (abstract pgf)) of + Just (ty,_,eqs) -> Just $ render (text "fun" <+> ppCId id <+> colon <+> ppType 0 [] ty $$ + if null eqs + then empty + else text "def" <+> vcat [let (scope,ds) = mapAccumL (ppPatt 9) [] patts + in ppCId id <+> hsep ds <+> char '=' <+> ppExpr 0 scope res | Equ patts res <- eqs]) + Nothing -> case Map.lookup id (cats (abstract pgf)) of + Just hyps -> Just $ render (text "cat" <+> ppCId id <+> hsep (snd (mapAccumL ppHypo [] hyps))) + Nothing -> Nothing + + (producers,consumers) = Map.foldWithKey accum ([],[]) (funs (abstract pgf)) + where + accum f (ty,_,_) (plist,clist) = + let !plist' = if id `elem` ps then f : plist else plist + !clist' = if id `elem` cs then f : clist else clist + in (plist',clist') + where + (ps,cs) = tyIds ty + + tyIds (DTyp hyps cat es) = (foldr expIds (cat:concat css) es,concat pss) + where + (pss,css) = unzip [tyIds ty | (_,_,ty) <- hyps] + + expIds (EAbs _ _ e) ids = expIds e ids + expIds (EApp e1 e2) ids = expIds e1 (expIds e2 ids) + expIds (EFun id) ids = id : ids + expIds (ETyped e _) ids = expIds e ids + expIds _ ids = ids diff --git a/src/runtime/haskell/PGF/Binary.hs b/src/runtime/haskell/PGF/Binary.hs new file mode 100644 index 000000000..e4ed98424 --- /dev/null +++ b/src/runtime/haskell/PGF/Binary.hs @@ -0,0 +1,199 @@ +module PGF.Binary where
+
+import PGF.CId
+import PGF.Data
+import Data.Binary
+import Data.Binary.Put
+import Data.Binary.Get
+import qualified Data.ByteString as BS
+import qualified Data.Map as Map
+import qualified Data.IntMap as IntMap
+import qualified Data.Set as Set
+import Control.Monad
+
+pgfMajorVersion, pgfMinorVersion :: Word16
+(pgfMajorVersion, pgfMinorVersion) = (1,0)
+
+instance Binary PGF where
+ put pgf = putWord16be pgfMajorVersion >>
+ putWord16be pgfMinorVersion >>
+ put ( absname pgf, cncnames pgf
+ , gflags pgf
+ , abstract pgf, concretes pgf
+ )
+ get = do v1 <- getWord16be
+ v2 <- getWord16be
+ absname <- get
+ cncnames <- get
+ gflags <- get
+ abstract <- get
+ concretes <- get
+ return (PGF{ absname=absname, cncnames=cncnames
+ , gflags=gflags
+ , abstract=abstract, concretes=concretes
+ })
+
+instance Binary CId where
+ put (CId bs) = put bs
+ get = liftM CId get
+
+instance Binary Abstr where
+ put abs = put (aflags abs, funs abs, cats abs)
+ get = do aflags <- get
+ funs <- get
+ cats <- get
+ let catfuns = Map.mapWithKey (\cat _ -> [f | (f, (DTyp _ c _,_,_)) <- Map.toList funs, c==cat]) cats
+ return (Abstr{ aflags=aflags
+ , funs=funs, cats=cats
+ , catfuns=catfuns
+ })
+
+instance Binary Concr where
+ put cnc = put ( cflags cnc, lins cnc, opers cnc
+ , lincats cnc, lindefs cnc
+ , printnames cnc, paramlincats cnc
+ , parser cnc
+ )
+ get = do cflags <- get
+ lins <- get
+ opers <- get
+ lincats <- get
+ lindefs <- get
+ printnames <- get
+ paramlincats <- get
+ parser <- get
+ return (Concr{ cflags=cflags, lins=lins, opers=opers
+ , lincats=lincats, lindefs=lindefs
+ , printnames=printnames
+ , paramlincats=paramlincats
+ , parser=parser
+ })
+
+instance Binary Alternative where
+ put (Alt v x) = put v >> put x
+ get = liftM2 Alt get get
+
+instance Binary Term where
+ put (R es) = putWord8 0 >> put es
+ put (S es) = putWord8 1 >> put es
+ put (FV es) = putWord8 2 >> put es
+ put (P e v) = putWord8 3 >> put (e,v)
+ put (W e v) = putWord8 4 >> put (e,v)
+ put (C i ) = putWord8 5 >> put i
+ put (TM i ) = putWord8 6 >> put i
+ put (F f) = putWord8 7 >> put f
+ put (V i) = putWord8 8 >> put i
+ put (K (KS s)) = putWord8 9 >> put s
+ put (K (KP d vs)) = putWord8 10 >> put (d,vs)
+
+ get = do tag <- getWord8
+ case tag of
+ 0 -> liftM R get
+ 1 -> liftM S get
+ 2 -> liftM FV get
+ 3 -> liftM2 P get get
+ 4 -> liftM2 W get get
+ 5 -> liftM C get
+ 6 -> liftM TM get
+ 7 -> liftM F get
+ 8 -> liftM V get
+ 9 -> liftM (K . KS) get
+ 10 -> liftM2 (\d vs -> K (KP d vs)) get get
+ _ -> decodingError
+
+instance Binary Expr where
+ put (EAbs b x exp) = putWord8 0 >> put (b,x,exp)
+ put (EApp e1 e2) = putWord8 1 >> put (e1,e2)
+ put (ELit (LStr s)) = putWord8 2 >> put s
+ put (ELit (LFlt d)) = putWord8 3 >> put d
+ put (ELit (LInt i)) = putWord8 4 >> put i
+ put (EMeta i) = putWord8 5 >> put i
+ put (EFun f) = putWord8 6 >> put f
+ put (EVar i) = putWord8 7 >> put i
+ put (ETyped e ty) = putWord8 8 >> put (e,ty)
+ get = do tag <- getWord8
+ case tag of
+ 0 -> liftM3 EAbs get get get
+ 1 -> liftM2 EApp get get
+ 2 -> liftM (ELit . LStr) get
+ 3 -> liftM (ELit . LFlt) get
+ 4 -> liftM (ELit . LInt) get
+ 5 -> liftM EMeta get
+ 6 -> liftM EFun get
+ 7 -> liftM EVar get
+ 8 -> liftM2 ETyped get get
+ _ -> decodingError
+
+instance Binary Patt where
+ put (PApp f ps) = putWord8 0 >> put (f,ps)
+ put (PVar x) = putWord8 1 >> put x
+ put PWild = putWord8 2
+ put (PLit (LStr s)) = putWord8 3 >> put s
+ put (PLit (LFlt d)) = putWord8 4 >> put d
+ put (PLit (LInt i)) = putWord8 5 >> put i
+ get = do tag <- getWord8
+ case tag of
+ 0 -> liftM2 PApp get get
+ 1 -> liftM PVar get
+ 2 -> return PWild
+ 3 -> liftM (PLit . LStr) get
+ 4 -> liftM (PLit . LFlt) get
+ 5 -> liftM (PLit . LInt) get
+ _ -> decodingError
+
+instance Binary Equation where
+ put (Equ ps e) = put (ps,e)
+ get = liftM2 Equ get get
+
+instance Binary Type where
+ put (DTyp hypos cat exps) = put (hypos,cat,exps)
+ get = liftM3 DTyp get get get
+
+instance Binary BindType where
+ put Explicit = putWord8 0
+ put Implicit = putWord8 1
+ get = do tag <- getWord8
+ case tag of
+ 0 -> return Explicit
+ 1 -> return Implicit
+ _ -> decodingError
+
+instance Binary FFun where
+ put (FFun fun prof lins) = put (fun,prof,lins)
+ get = liftM3 FFun get get get
+
+instance Binary FSymbol where
+ put (FSymCat n l) = putWord8 0 >> put (n,l)
+ put (FSymLit n l) = putWord8 1 >> put (n,l)
+ put (FSymKS ts) = putWord8 2 >> put ts
+ put (FSymKP d vs) = putWord8 3 >> put (d,vs)
+ get = do tag <- getWord8
+ case tag of
+ 0 -> liftM2 FSymCat get get
+ 1 -> liftM2 FSymLit get get
+ 2 -> liftM FSymKS get
+ 3 -> liftM2 (\d vs -> FSymKP d vs) get get
+ _ -> decodingError
+
+instance Binary Production where
+ put (FApply ruleid args) = putWord8 0 >> put (ruleid,args)
+ put (FCoerce fcat) = putWord8 1 >> put fcat
+ get = do tag <- getWord8
+ case tag of
+ 0 -> liftM2 FApply get get
+ 1 -> liftM FCoerce get
+ _ -> decodingError
+
+instance Binary ParserInfo where
+ put p = put (functions p, sequences p, productions0 p, totalCats p, startCats p)
+ get = do functions <- get
+ sequences <- get
+ productions0<- get
+ totalCats <- get
+ startCats <- get
+ return (ParserInfo{functions=functions,sequences=sequences
+ ,productions0=productions0
+ ,productions =filterProductions productions0
+ ,totalCats=totalCats,startCats=startCats})
+
+decodingError = fail "This PGF file was compiled with different version of GF"
diff --git a/src/runtime/haskell/PGF/BuildParser.hs b/src/runtime/haskell/PGF/BuildParser.hs new file mode 100644 index 000000000..23e0725c6 --- /dev/null +++ b/src/runtime/haskell/PGF/BuildParser.hs @@ -0,0 +1,76 @@ +--------------------------------------------------------------------- +-- | +-- Maintainer : Krasimir Angelov +-- Stability : (stable) +-- Portability : (portable) +-- +-- FCFG parsing, parser information +----------------------------------------------------------------------------- + +module PGF.BuildParser where + +import GF.Data.SortedList +import GF.Data.Assoc +import PGF.CId +import PGF.Data +import PGF.Parsing.FCFG.Utilities + +import Data.Array.IArray +import Data.Maybe +import qualified Data.IntMap as IntMap +import qualified Data.Map as Map +import qualified Data.Set as Set +import Debug.Trace + + +data ParserInfoEx + = ParserInfoEx { epsilonRules :: [(FunId,[FCat],FCat)] + , leftcornerCats :: Assoc FCat [(FunId,[FCat],FCat)] + , leftcornerTokens :: Assoc String [(FunId,[FCat],FCat)] + , grammarToks :: [String] + } + +------------------------------------------------------------ +-- parser information + +getLeftCornerTok pinfo (FFun _ _ lins) + | inRange (bounds syms) 0 = case syms ! 0 of + FSymKS [tok] -> [tok] + _ -> [] + | otherwise = [] + where + syms = (sequences pinfo) ! (lins ! 0) + +getLeftCornerCat pinfo args (FFun _ _ lins) + | inRange (bounds syms) 0 = case syms ! 0 of + FSymCat d _ -> let cat = args !! d + in case IntMap.lookup cat (productions pinfo) of + Just set -> cat : [cat' | FCoerce cat' <- Set.toList set] + Nothing -> [cat] + _ -> [] + | otherwise = [] + where + syms = (sequences pinfo) ! (lins ! 0) + +buildParserInfo :: ParserInfo -> ParserInfoEx +buildParserInfo pinfo = + ParserInfoEx { epsilonRules = epsilonrules + , leftcornerCats = leftcorncats + , leftcornerTokens = leftcorntoks + , grammarToks = grammartoks + } + + where epsilonrules = [ (ruleid,args,cat) + | (cat,set) <- IntMap.toList (productions pinfo) + , (FApply ruleid args) <- Set.toList set + , let (FFun _ _ lins) = (functions pinfo) ! ruleid + , not (inRange (bounds ((sequences pinfo) ! (lins ! 0))) 0) ] + leftcorncats = accumAssoc id [ (cat', (ruleid, args, cat)) + | (cat,set) <- IntMap.toList (productions pinfo) + , (FApply ruleid args) <- Set.toList set + , cat' <- getLeftCornerCat pinfo args ((functions pinfo) ! ruleid) ] + leftcorntoks = accumAssoc id [ (tok, (ruleid, args, cat)) + | (cat,set) <- IntMap.toList (productions pinfo) + , (FApply ruleid args) <- Set.toList set + , tok <- getLeftCornerTok pinfo ((functions pinfo) ! ruleid) ] + grammartoks = nubsort [t | lin <- elems (sequences pinfo), FSymKS [t] <- elems lin] diff --git a/src/runtime/haskell/PGF/CId.hs b/src/runtime/haskell/PGF/CId.hs new file mode 100644 index 000000000..fea304d9d --- /dev/null +++ b/src/runtime/haskell/PGF/CId.hs @@ -0,0 +1,55 @@ +module PGF.CId (CId(..), + mkCId, wildCId, + readCId, showCId, + + -- utils + pCId, pIdent, ppCId) where + +import Control.Monad +import qualified Data.ByteString.Char8 as BS +import Data.Char +import qualified Text.ParserCombinators.ReadP as RP +import qualified Text.PrettyPrint as PP + + +-- | An abstract data type that represents +-- identifiers for functions and categories in PGF. +newtype CId = CId BS.ByteString deriving (Eq,Ord) + +wildCId :: CId +wildCId = CId (BS.singleton '_') + +-- | Creates a new identifier from 'String' +mkCId :: String -> CId +mkCId s = CId (BS.pack s) + +-- | Reads an identifier from 'String'. The function returns 'Nothing' if the string is not valid identifier. +readCId :: String -> Maybe CId +readCId s = case [x | (x,cs) <- RP.readP_to_S pCId s, all isSpace cs] of + [x] -> Just x + _ -> Nothing + +-- | Renders the identifier as 'String' +showCId :: CId -> String +showCId (CId x) = BS.unpack x + +instance Show CId where + showsPrec _ = showString . showCId + +instance Read CId where + readsPrec _ = RP.readP_to_S pCId + +pCId :: RP.ReadP CId +pCId = do s <- pIdent + if s == "_" + then RP.pfail + else return (mkCId s) + +pIdent :: RP.ReadP String +pIdent = liftM2 (:) (RP.satisfy isIdentFirst) (RP.munch isIdentRest) + where + isIdentFirst c = c == '_' || isLetter c + isIdentRest c = c == '_' || c == '\'' || isAlphaNum c + +ppCId :: CId -> PP.Doc +ppCId = PP.text . showCId diff --git a/src/runtime/haskell/PGF/Check.hs b/src/runtime/haskell/PGF/Check.hs new file mode 100644 index 000000000..58b66cfe4 --- /dev/null +++ b/src/runtime/haskell/PGF/Check.hs @@ -0,0 +1,173 @@ +module PGF.Check (checkPGF) where + +import PGF.CId +import PGF.Data +import PGF.Macros +import GF.Data.ErrM + +import qualified Data.Map as Map +import Control.Monad +import Debug.Trace + +checkPGF :: PGF -> Err (PGF,Bool) +checkPGF pgf = do + (cs,bs) <- mapM (checkConcrete pgf) + (Map.assocs (concretes pgf)) >>= return . unzip + return (pgf {concretes = Map.fromAscList cs}, and bs) + + +-- errors are non-fatal; replace with 'fail' to change this +msg s = trace s (return ()) + +andMapM :: Monad m => (a -> m Bool) -> [a] -> m Bool +andMapM f xs = mapM f xs >>= return . and + +labelBoolErr :: String -> Err (x,Bool) -> Err (x,Bool) +labelBoolErr ms iob = do + (x,b) <- iob + if b then return (x,b) else (msg ms >> return (x,b)) + + +checkConcrete :: PGF -> (CId,Concr) -> Err ((CId,Concr),Bool) +checkConcrete pgf (lang,cnc) = + labelBoolErr ("happened in language " ++ showCId lang) $ do + (rs,bs) <- mapM checkl (Map.assocs (lins cnc)) >>= return . unzip + return ((lang,cnc{lins = Map.fromAscList rs}),and bs) + where + checkl = checkLin pgf lang + +checkLin :: PGF -> CId -> (CId,Term) -> Err ((CId,Term),Bool) +checkLin pgf lang (f,t) = + labelBoolErr ("happened in function " ++ showCId f) $ do + (t',b) <- checkTerm (lintype pgf lang f) t --- $ inline pgf lang t + return ((f,t'),b) + +inferTerm :: [CType] -> Term -> Err (Term,CType) +inferTerm args trm = case trm of + K _ -> returnt str + C i -> returnt $ ints i + V i -> do + testErr (i < length args) ("too large index " ++ show i) + returnt $ args !! i + S ts -> do + (ts',tys) <- mapM infer ts >>= return . unzip + let tys' = filter (/=str) tys + testErr (null tys') + ("expected Str in " ++ show trm ++ " not " ++ unwords (map show tys')) + return (S ts',str) + R ts -> do + (ts',tys) <- mapM infer ts >>= return . unzip + return $ (R ts',tuple tys) + P t u -> do + (t',tt) <- infer t + (u',tu) <- infer u + case tt of + R tys -> case tu of + R vs -> infer $ foldl P t' [P u' (C i) | i <- [0 .. length vs - 1]] + --- R [v] -> infer $ P t v + --- R (v:vs) -> infer $ P (head tys) (R vs) + + C i -> do + testErr (i < length tys) + ("required more than " ++ show i ++ " fields in " ++ show (R tys)) + return (P t' u', tys !! i) -- record: index must be known + _ -> do + let typ = head tys + testErr (all (==typ) tys) ("different types in table " ++ show trm) + return (P t' u', typ) -- table: types must be same + _ -> Bad $ "projection from " ++ show t ++ " : " ++ show tt + FV [] -> returnt tm0 ---- + FV (t:ts) -> do + (t',ty) <- infer t + (ts',tys) <- mapM infer ts >>= return . unzip + testErr (all (eqType True ty) tys) ("different types in variants " ++ show trm) + return (FV (t':ts'),ty) + W s r -> infer r + _ -> Bad ("no type inference for " ++ show trm) + where + returnt ty = return (trm,ty) + infer = inferTerm args + +checkTerm :: LinType -> Term -> Err (Term,Bool) +checkTerm (args,val) trm = case inferTerm args trm of + Ok (t,ty) -> if eqType False ty val + then return (t,True) + else do + msg ("term: " ++ show trm ++ + "\nexpected type: " ++ show val ++ + "\ninferred type: " ++ show ty) + return (t,False) + Bad s -> do + msg s + return (trm,False) + +-- symmetry in (Ints m == Ints n) is all we can use in variants + +eqType :: Bool -> CType -> CType -> Bool +eqType symm inf exp = case (inf,exp) of + (C k, C n) -> if symm then True else k <= n -- only run-time corr. + (R rs,R ts) -> length rs == length ts && and [eqType symm r t | (r,t) <- zip rs ts] + (TM _, _) -> True ---- for variants [] ; not safe + _ -> inf == exp + +-- should be in a generic module, but not in the run-time DataGFCC + +type CType = Term +type LinType = ([CType],CType) + +tuple :: [CType] -> CType +tuple = R + +ints :: Int -> CType +ints = C + +str :: CType +str = S [] + +lintype :: PGF -> CId -> CId -> LinType +lintype pgf lang fun = case typeSkeleton (lookType pgf fun) of + (cs,c) -> (map vlinc cs, linc c) ---- HOAS + where + linc = lookLincat pgf lang + vlinc (0,c) = linc c + vlinc (i,c) = case linc c of + R ts -> R (ts ++ replicate i str) + +inline :: PGF -> CId -> Term -> Term +inline pgf lang t = case t of + F c -> inl $ look c + _ -> composSafeOp inl t + where + inl = inline pgf lang + look = lookLin pgf lang + +composOp :: Monad m => (Term -> m Term) -> Term -> m Term +composOp f trm = case trm of + R ts -> liftM R $ mapM f ts + S ts -> liftM S $ mapM f ts + FV ts -> liftM FV $ mapM f ts + P t u -> liftM2 P (f t) (f u) + W s t -> liftM (W s) $ f t + _ -> return trm + +composSafeOp :: (Term -> Term) -> Term -> Term +composSafeOp f = maybe undefined id . composOp (return . f) + +-- from GF.Data.Oper + +maybeErr :: String -> Maybe a -> Err a +maybeErr s = maybe (Bad s) Ok + +testErr :: Bool -> String -> Err () +testErr cond msg = if cond then return () else Bad msg + +errVal :: a -> Err a -> a +errVal a = err (const a) id + +errIn :: String -> Err a -> Err a +errIn msg = err (\s -> Bad (s ++ "\nOCCURRED IN\n" ++ msg)) return + +err :: (String -> b) -> (a -> b) -> Err a -> b +err d f e = case e of + Ok a -> f a + Bad s -> d s diff --git a/src/runtime/haskell/PGF/Data.hs b/src/runtime/haskell/PGF/Data.hs new file mode 100644 index 000000000..38027e96e --- /dev/null +++ b/src/runtime/haskell/PGF/Data.hs @@ -0,0 +1,95 @@ +module PGF.Data (module PGF.Data, module PGF.Expr, module PGF.Type, module PGF.PMCFG) where + +import PGF.CId +import PGF.Expr hiding (Value, Env, Tree) +import PGF.Type +import PGF.PMCFG + +import qualified Data.Map as Map +import qualified Data.Set as Set +import qualified Data.IntMap as IntMap +import Data.List + +-- internal datatypes for PGF + +-- | An abstract data type representing multilingual grammar +-- in Portable Grammar Format. +data PGF = PGF { + absname :: CId , + cncnames :: [CId] , + gflags :: Map.Map CId String, -- value of a global flag + abstract :: Abstr , + concretes :: Map.Map CId Concr + } + +data Abstr = Abstr { + aflags :: Map.Map CId String, -- value of a flag + funs :: Map.Map CId (Type,Int,[Equation]), -- type, arrity and definition of function + cats :: Map.Map CId [Hypo], -- context of a cat + catfuns :: Map.Map CId [CId] -- funs to a cat (redundant, for fast lookup) + } + +data Concr = Concr { + cflags :: Map.Map CId String, -- value of a flag + lins :: Map.Map CId Term, -- lin of a fun + opers :: Map.Map CId Term, -- oper generated by subex elim + lincats :: Map.Map CId Term, -- lin type of a cat + lindefs :: Map.Map CId Term, -- lin default of a cat + printnames :: Map.Map CId Term, -- printname of a cat or a fun + paramlincats :: Map.Map CId Term, -- lin type of cat, with printable param names + parser :: Maybe ParserInfo -- parser + } + +data Term = + R [Term] + | P Term Term + | S [Term] + | K Tokn + | V Int + | C Int + | F CId + | FV [Term] + | W String Term + | TM String + deriving (Eq,Ord,Show) + +data Tokn = + KS String + | KP [String] [Alternative] + deriving (Eq,Ord,Show) + + +-- merge two GFCCs; fails is differens absnames; priority to second arg + +unionPGF :: PGF -> PGF -> PGF +unionPGF one two = case absname one of + n | n == wildCId -> two -- extending empty grammar + | n == absname two -> one { -- extending grammar with same abstract + concretes = Map.union (concretes two) (concretes one), + cncnames = union (cncnames one) (cncnames two) + } + _ -> one -- abstracts don't match ---- print error msg + +emptyPGF :: PGF +emptyPGF = PGF { + absname = wildCId, + cncnames = [] , + gflags = Map.empty, + abstract = error "empty grammar, no abstract", + concretes = Map.empty + } + +-- | This is just a 'CId' with the language name. +-- A language name is the identifier that you write in the +-- top concrete or abstract module in GF after the +-- concrete/abstract keyword. Example: +-- +-- > abstract Lang = ... +-- > concrete LangEng of Lang = ... +type Language = CId + +readLanguage :: String -> Maybe Language +readLanguage = readCId + +showLanguage :: Language -> String +showLanguage = showCId diff --git a/src/runtime/haskell/PGF/Editor.hs b/src/runtime/haskell/PGF/Editor.hs new file mode 100644 index 000000000..3f69da170 --- /dev/null +++ b/src/runtime/haskell/PGF/Editor.hs @@ -0,0 +1,241 @@ +module PGF.Editor ( + State, -- datatype -- type-annotated possibly open tree with a focus + Dict, -- datatype -- abstract syntax information optimized for editing + Position, -- datatype -- path from top to focus + new, -- :: Type -> State -- create new State + refine, -- :: Dict -> CId -> State -> State -- refine focus with CId + replace, -- :: Dict -> Tree -> State -> State -- replace focus with Tree + delete, -- :: State -> State -- replace focus with ? + goNextMeta, -- :: State -> State -- move focus to next ? node + goNext, -- :: State -> State -- move to next node + goTop, -- :: State -> State -- move focus to the top (=root) + goPosition, -- :: Position -> State -> State -- move focus to given position + mkPosition, -- :: [Int] -> Position -- list of choices (top = []) + showPosition,-- :: Position -> [Int] -- readable position + focusType, -- :: State -> Type -- get the type of focus + stateTree, -- :: State -> Tree -- get the current tree + isMetaFocus, -- :: State -> Bool -- whether focus is ? + allMetas, -- :: State -> [(Position,Type)] -- all ?s and their positions + prState, -- :: State -> String -- print state, focus marked * + refineMenu, -- :: Dict -> State -> [CId] -- get refinement menu + pgf2dict -- :: PGF -> Dict -- create editing Dict from PGF + ) where + +import PGF.Data +import PGF.CId +import qualified Data.Map as M +import Debug.Trace ---- + +-- API + +new :: Type -> State +new (DTyp _ t _) = etree2state (uETree t) + +refine :: Dict -> CId -> State -> State +refine dict f = replaceInState (mkRefinement dict f) + +replace :: Dict -> Tree -> State -> State +replace dict t = replaceInState (tree2etree dict t) + +delete :: State -> State +delete s = replaceInState (uETree (typ (tree s))) s + +goNextMeta :: State -> State +goNextMeta s = + if isComplete s then s + else let s1 = goNext s in if isMetaFocus s1 + then s1 else goNextMeta s1 + +isComplete :: State -> Bool +isComplete s = isc (tree s) where + isc t = case atom t of + AMeta _ -> False + ACon _ -> all isc (children t) + +goTop :: State -> State +goTop = navigate (const top) + +goPosition :: [Int] -> State -> State +goPosition p s = s{position = p} + +mkPosition :: [Int] -> Position +mkPosition = id + +refineMenu :: Dict -> State -> [CId] +refineMenu dict s = maybe [] (map fst) $ M.lookup (focusBType s) (refines dict) + +focusType :: State -> Type +focusType s = btype2type (focusBType s) + +stateTree :: State -> Tree +stateTree = etree2tree . tree + +pgf2dict :: PGF -> Dict +pgf2dict pgf = Dict (M.fromAscList fus) refs where + fus = [(f,mkFType ty) | (f,(ty,_)) <- M.toList (funs abs)] + refs = M.fromAscList [(c, fusTo c) | (c,_) <- M.toList (cats abs)] + fusTo c = [(f,ty) | (f,ty@(_,k)) <- fus, k==c] ---- quadratic + mkFType (DTyp hyps c _) = ([k | Hyp _ (DTyp _ k _) <- hyps],c) ----dep types + abs = abstract pgf + +etree2tree :: ETree -> Tree +etree2tree t = case atom t of + ACon f -> Fun f (map etree2tree (children t)) + AMeta i -> Meta i + +tree2etree :: Dict -> Tree -> ETree +tree2etree dict t = case t of + Fun f _ -> annot (look f) t + where + annot (tys,ty) tr = case tr of + Fun f trs -> ETree (ACon f) ty [annt t tr | (t,tr) <- zip tys trs] + Meta i -> ETree (AMeta i) ty [] + annt ty tr = case tr of + Fun _ _ -> tree2etree dict tr + Meta _ -> annot ([],ty) tr + look f = maybe undefined id $ M.lookup f (functs dict) + +prState :: State -> String +prState s = unlines [replicate i ' ' ++ f | (i,f) <- pr [] (tree s)] where + pr i t = + (ind i,prAtom i (atom t)) : concat [pr (sub j i) c | (j,c) <- zip [0..] (children t)] + prAtom i a = prFocus i ++ case a of + ACon f -> prCId f + AMeta i -> "?" ++ show i + prFocus i = if i == position s then "*" else "" + ind i = 2 * length i + sub j i = i ++ [j] + +showPosition :: Position -> [Int] +showPosition = id + +allMetas :: State -> [(Position,Type)] +allMetas s = [(reverse p, btype2type ty) | (p,ty) <- metas [] (tree s)] where + metas p t = + (if isMetaAtom (atom t) then [(p,typ t)] else []) ++ + concat [metas (i:p) u | (i,u) <- zip [0..] (children t)] + +---- Trees and navigation + +data ETree = ETree { + atom :: Atom, + typ :: BType, + children :: [ETree] + } + deriving Show + +data Atom = + ACon CId + | AMeta Int + deriving Show + +btype2type :: BType -> Type +btype2type t = DTyp [] t [] + +uETree :: BType -> ETree +uETree ty = ETree (AMeta 0) ty [] + +data State = State { + position :: Position, + tree :: ETree + } + deriving Show + +type Position = [Int] + +top :: Position +top = [] + +up :: Position -> Position +up p = case p of + _:_ -> init p + _ -> p + +down :: Position -> Position +down = (++[0]) + +left :: Position -> Position +left p = case p of + _:_ | last p > 0 -> init p ++ [last p - 1] + _ -> top + +right :: Position -> Position +right p = case p of + _:_ -> init p ++ [last p + 1] + _ -> top + +etree2state :: ETree -> State +etree2state = State top + +doInState :: (ETree -> ETree) -> State -> State +doInState f s = s{tree = change (position s) (tree s)} where + change p t = case p of + [] -> f t + n:ns -> let (ts1,t0:ts2) = splitAt n (children t) in + t{children = ts1 ++ [change ns t0] ++ ts2} + +subtree :: Position -> ETree -> ETree +subtree p t = case p of + [] -> t + n:ns -> subtree ns (children t !! n) + +focus :: State -> ETree +focus s = subtree (position s) (tree s) + +focusBType :: State -> BType +focusBType s = typ (focus s) + +navigate :: (Position -> Position) -> State -> State +navigate p s = s{position = p (position s)} + +-- p is a fix-point aspect of state change +untilFix :: Eq a => (State -> a) -> (State -> Bool) -> (State -> State) -> State -> State +untilFix p b f s = + if b s + then s + else let fs = f s in if p fs == p s + then s + else untilFix p b f fs + +untilPosition :: (State -> Bool) -> (State -> State) -> State -> State +untilPosition = untilFix position + +goNext :: State -> State +goNext s = case focus s of + st | not (null (children st)) -> navigate down s + _ -> findSister s + where + findSister s = case s of + s' | null (position s') -> s' + s' | hasYoungerSisters s' -> navigate right s' + s' -> findSister (navigate up s') + hasYoungerSisters s = case position s of + p@(_:_) -> length (children (focus (navigate up s))) > last p + 1 + _ -> False + +isMetaFocus :: State -> Bool +isMetaFocus s = isMetaAtom (atom (focus s)) + +isMetaAtom :: Atom -> Bool +isMetaAtom a = case a of + AMeta _ -> True + _ -> False + +replaceInState :: ETree -> State -> State +replaceInState t = doInState (const t) + + +------- + +type BType = CId ----dep types +type FType = ([BType],BType) ----dep types + +data Dict = Dict { + functs :: M.Map CId FType, + refines :: M.Map BType [(CId,FType)] + } + +mkRefinement :: Dict -> CId -> ETree +mkRefinement dict f = ETree (ACon f) val (map uETree args) where + (args,val) = maybe undefined id $ M.lookup f (functs dict) + diff --git a/src/runtime/haskell/PGF/Expr.hs b/src/runtime/haskell/PGF/Expr.hs new file mode 100644 index 000000000..cf0cb79aa --- /dev/null +++ b/src/runtime/haskell/PGF/Expr.hs @@ -0,0 +1,355 @@ +module PGF.Expr(Tree, BindType(..), Expr(..), Literal(..), Patt(..), Equation(..),
+ readExpr, showExpr, pExpr, pBinds, ppExpr, ppPatt,
+
+ mkApp, unApp,
+ mkStr, unStr,
+ mkInt, unInt,
+ mkDouble, unDouble,
+ mkMeta, isMeta,
+
+ normalForm,
+
+ -- needed in the typechecker
+ Value(..), Env, Funs, eval, apply,
+
+ MetaId,
+
+ -- helpers
+ pMeta,pStr,pArg,pLit,freshName,ppMeta,ppLit,ppParens
+ ) where
+
+import PGF.CId
+import PGF.Type
+
+import Data.Char
+import Data.Maybe
+import Data.List as List
+import Data.Map as Map hiding (showTree)
+import Control.Monad
+import qualified Text.PrettyPrint as PP
+import qualified Text.ParserCombinators.ReadP as RP
+
+data Literal =
+ LStr String -- ^ string constant
+ | LInt Integer -- ^ integer constant
+ | LFlt Double -- ^ floating point constant
+ deriving (Eq,Ord,Show)
+
+type MetaId = Int
+
+data BindType =
+ Explicit
+ | Implicit
+ deriving (Eq,Ord,Show)
+
+-- | Tree is the abstract syntax representation of a given sentence
+-- in some concrete syntax. Technically 'Tree' is a type synonym
+-- of 'Expr'.
+type Tree = Expr
+
+-- | An expression in the abstract syntax of the grammar. It could be
+-- both parameter of a dependent type or an abstract syntax tree for
+-- for some sentence.
+data Expr =
+ EAbs BindType CId Expr -- ^ lambda abstraction
+ | EApp Expr Expr -- ^ application
+ | ELit Literal -- ^ literal
+ | EMeta {-# UNPACK #-} !MetaId -- ^ meta variable
+ | EFun CId -- ^ function or data constructor
+ | EVar {-# UNPACK #-} !Int -- ^ variable with de Bruijn index
+ | ETyped Expr Type -- ^ local type signature
+ | EImplArg Expr -- ^ implicit argument in expression
+ deriving (Eq,Ord,Show)
+
+-- | The pattern is used to define equations in the abstract syntax of the grammar.
+data Patt =
+ PApp CId [Patt] -- ^ application. The identifier should be constructor i.e. defined with 'data'
+ | PLit Literal -- ^ literal
+ | PVar CId -- ^ variable
+ | PWild -- ^ wildcard
+ | PImplArg Patt -- ^ implicit argument in pattern
+ deriving (Eq,Ord)
+
+-- | The equation is used to define lambda function as a sequence
+-- of equations with pattern matching. The list of 'Expr' represents
+-- the patterns and the second 'Expr' is the function body for this
+-- equation.
+data Equation =
+ Equ [Patt] Expr
+ deriving (Eq,Ord)
+
+-- | parses 'String' as an expression
+readExpr :: String -> Maybe Expr
+readExpr s = case [x | (x,cs) <- RP.readP_to_S pExpr s, all isSpace cs] of
+ [x] -> Just x
+ _ -> Nothing
+
+-- | renders expression as 'String'. The list
+-- of identifiers is the list of all free variables
+-- in the expression in order reverse to the order
+-- of binding.
+showExpr :: [CId] -> Expr -> String
+showExpr vars = PP.render . ppExpr 0 vars
+
+instance Read Expr where
+ readsPrec _ = RP.readP_to_S pExpr
+
+-- | Constructs an expression by applying a function to a list of expressions
+mkApp :: CId -> [Expr] -> Expr
+mkApp f es = foldl EApp (EFun f) es
+
+-- | Decomposes an expression into application of function
+unApp :: Expr -> Maybe (CId,[Expr])
+unApp = extract []
+ where
+ extract es (EFun f) = Just (f,es)
+ extract es (EApp e1 e2) = extract (e2:es) e1
+ extract es _ = Nothing
+
+-- | Constructs an expression from string literal
+mkStr :: String -> Expr
+mkStr s = ELit (LStr s)
+
+-- | Decomposes an expression into string literal
+unStr :: Expr -> Maybe String
+unStr (ELit (LStr s)) = Just s
+unStr _ = Nothing
+
+-- | Constructs an expression from integer literal
+mkInt :: Integer -> Expr
+mkInt i = ELit (LInt i)
+
+-- | Decomposes an expression into integer literal
+unInt :: Expr -> Maybe Integer
+unInt (ELit (LInt i)) = Just i
+unInt _ = Nothing
+
+-- | Constructs an expression from real number literal
+mkDouble :: Double -> Expr
+mkDouble f = ELit (LFlt f)
+
+-- | Decomposes an expression into real number literal
+unDouble :: Expr -> Maybe Double
+unDouble (ELit (LFlt f)) = Just f
+unDouble _ = Nothing
+
+-- | Constructs an expression which is meta variable
+mkMeta :: Expr
+mkMeta = EMeta 0
+
+-- | Checks whether an expression is a meta variable
+isMeta :: Expr -> Bool
+isMeta (EMeta _) = True
+isMeta _ = False
+
+-----------------------------------------------------
+-- Parsing
+-----------------------------------------------------
+
+pExpr :: RP.ReadP Expr
+pExpr = RP.skipSpaces >> (pAbs RP.<++ pTerm)
+ where
+ pTerm = do f <- pFactor
+ RP.skipSpaces
+ as <- RP.sepBy pArg RP.skipSpaces
+ return (foldl EApp f as)
+
+ pAbs = do xs <- RP.between (RP.char '\\') (RP.skipSpaces >> RP.string "->") pBinds
+ e <- pExpr
+ return (foldr (\(b,x) e -> EAbs b x e) e xs)
+
+pBinds :: RP.ReadP [(BindType,CId)]
+pBinds = do xss <- RP.sepBy1 (RP.skipSpaces >> pBind) (RP.skipSpaces >> RP.char ',')
+ return (concat xss)
+ where
+ pCIdOrWild = pCId `mplus` (RP.char '_' >> return wildCId)
+
+ pBind =
+ do x <- pCIdOrWild
+ return [(Explicit,x)]
+ `mplus`
+ RP.between (RP.char '{')
+ (RP.skipSpaces >> RP.char '}')
+ (RP.sepBy1 (RP.skipSpaces >> pCIdOrWild >>= \id -> return (Implicit,id)) (RP.skipSpaces >> RP.char ','))
+
+pArg = fmap EImplArg (RP.between (RP.char '{') (RP.char '}') pExpr)
+ RP.<++
+ pFactor
+
+pFactor = fmap EFun pCId
+ RP.<++ fmap ELit pLit
+ RP.<++ fmap EMeta pMeta
+ RP.<++ RP.between (RP.char '(') (RP.char ')') pExpr
+ RP.<++ RP.between (RP.char '<') (RP.char '>') pTyped
+
+pTyped = do RP.skipSpaces
+ e <- pExpr
+ RP.skipSpaces
+ RP.char ':'
+ RP.skipSpaces
+ ty <- pType
+ return (ETyped e ty)
+
+pMeta = do RP.char '?'
+ return 0
+
+pLit :: RP.ReadP Literal
+pLit = pNum RP.<++ liftM LStr pStr
+
+pNum = do x <- RP.munch1 isDigit
+ ((RP.char '.' >> RP.munch1 isDigit >>= \y -> return (LFlt (read (x++"."++y))))
+ RP.<++
+ (return (LInt (read x))))
+
+pStr = RP.char '"' >> (RP.manyTill (pEsc RP.<++ RP.get) (RP.char '"'))
+ where
+ pEsc = RP.char '\\' >> RP.get
+
+
+-----------------------------------------------------
+-- Printing
+-----------------------------------------------------
+
+ppExpr :: Int -> [CId] -> Expr -> PP.Doc
+ppExpr d scope (EAbs b x e) = let (bs,xs,e1) = getVars [] [] (EAbs b x e)
+ in ppParens (d > 1) (PP.char '\\' PP.<>
+ PP.hsep (PP.punctuate PP.comma (reverse (List.zipWith ppBind bs xs))) PP.<+>
+ PP.text "->" PP.<+>
+ ppExpr 1 (xs++scope) e1)
+ where
+ getVars bs xs (EAbs b x e) = getVars (b:bs) ((freshName x xs):xs) e
+ getVars bs xs e = (bs,xs,e)
+ppExpr d scope (EApp e1 e2) = ppParens (d > 3) ((ppExpr 3 scope e1) PP.<+> (ppExpr 4 scope e2))
+ppExpr d scope (ELit l) = ppLit l
+ppExpr d scope (EMeta n) = ppMeta n
+ppExpr d scope (EFun f) = ppCId f
+ppExpr d scope (EVar i) = ppCId (scope !! i)
+ppExpr d scope (ETyped e ty)= PP.char '<' PP.<> ppExpr 0 scope e PP.<+> PP.colon PP.<+> ppType 0 scope ty PP.<> PP.char '>'
+ppExpr d scope (EImplArg e) = PP.braces (ppExpr 0 scope e)
+
+ppPatt :: Int -> [CId] -> Patt -> ([CId],PP.Doc)
+ppPatt d scope (PApp f ps) = let (scope',ds) = mapAccumL (ppPatt 2) scope ps
+ in (scope',ppParens (not (List.null ps) && d > 1) (ppCId f PP.<+> PP.hsep ds))
+ppPatt d scope (PLit l) = (scope,ppLit l)
+ppPatt d scope (PVar f) = (f:scope,ppCId f)
+ppPatt d scope PWild = (scope,PP.char '_')
+ppPatt d scope (PImplArg p) = let (scope',d) = ppPatt 0 scope p
+ in (scope',PP.braces d)
+
+ppBind Explicit x = ppCId x
+ppBind Implicit x = PP.braces (ppCId x)
+
+ppLit (LStr s) = PP.text (show s)
+ppLit (LInt n) = PP.integer n
+ppLit (LFlt d) = PP.double d
+
+ppMeta :: MetaId -> PP.Doc
+ppMeta n
+ | n == 0 = PP.char '?'
+ | otherwise = PP.char '?' PP.<> PP.int n
+
+ppParens True = PP.parens
+ppParens False = id
+
+freshName :: CId -> [CId] -> CId
+freshName x xs0 = loop 1 x
+ where
+ xs = wildCId : xs0
+
+ loop i y
+ | elem y xs = loop (i+1) (mkCId (show x++show i))
+ | otherwise = y
+
+
+-----------------------------------------------------
+-- Computation
+-----------------------------------------------------
+
+-- | Compute an expression to normal form
+normalForm :: Funs -> Int -> Env -> Expr -> Expr
+normalForm funs k env e = value2expr k (eval funs env e)
+ where
+ value2expr i (VApp f vs) = foldl EApp (EFun f) (List.map (value2expr i) vs)
+ value2expr i (VGen j vs) = foldl EApp (EVar (i-j-1)) (List.map (value2expr i) vs)
+ value2expr i (VMeta j env vs) = foldl EApp (EMeta j) (List.map (value2expr i) vs)
+ value2expr i (VSusp j env vs k) = value2expr i (k (VGen j vs))
+ value2expr i (VLit l) = ELit l
+ value2expr i (VClosure env (EAbs b x e)) = EAbs b x (value2expr (i+1) (eval funs ((VGen i []):env) e))
+ value2expr i (VImplArg v) = EImplArg (value2expr i v)
+
+data Value
+ = VApp CId [Value]
+ | VLit Literal
+ | VMeta {-# UNPACK #-} !MetaId Env [Value]
+ | VSusp {-# UNPACK #-} !MetaId Env [Value] (Value -> Value)
+ | VGen {-# UNPACK #-} !Int [Value]
+ | VClosure Env Expr
+ | VImplArg Value
+
+type Funs = Map.Map CId (Type,Int,[Equation]) -- type and def of a fun
+type Env = [Value]
+
+eval :: Funs -> Env -> Expr -> Value
+eval funs env (EVar i) = env !! i
+eval funs env (EFun f) = case Map.lookup f funs of
+ Just (_,a,eqs) -> if a == 0
+ then case eqs of
+ Equ [] e : _ -> eval funs [] e
+ _ -> VApp f []
+ else VApp f []
+ Nothing -> error ("unknown function "++showCId f)
+eval funs env (EApp e1 e2) = apply funs env e1 [eval funs env e2]
+eval funs env (EAbs b x e) = VClosure env (EAbs b x e)
+eval funs env (EMeta i) = VMeta i env []
+eval funs env (ELit l) = VLit l
+eval funs env (ETyped e _) = eval funs env e
+eval funs env (EImplArg e) = VImplArg (eval funs env e)
+
+apply :: Funs -> Env -> Expr -> [Value] -> Value
+apply funs env e [] = eval funs env e
+apply funs env (EVar i) vs = applyValue funs (env !! i) vs
+apply funs env (EFun f) vs = case Map.lookup f funs of
+ Just (_,a,eqs) -> if a <= length vs
+ then let (as,vs') = splitAt a vs
+ in match funs f eqs as vs'
+ else VApp f vs
+ Nothing -> error ("unknown function "++showCId f)
+apply funs env (EApp e1 e2) vs = apply funs env e1 (eval funs env e2 : vs)
+apply funs env (EAbs _ x e) (v:vs) = apply funs (v:env) e vs
+apply funs env (EMeta i) vs = VMeta i env vs
+apply funs env (ELit l) vs = error "literal of function type"
+apply funs env (ETyped e _) vs = apply funs env e vs
+apply funs env (EImplArg _) vs = error "implicit argument in function position"
+
+applyValue funs v [] = v
+applyValue funs (VApp f vs0) vs = apply funs [] (EFun f) (vs0++vs)
+applyValue funs (VLit _) vs = error "literal of function type"
+applyValue funs (VMeta i env vs0) vs = VMeta i env (vs0++vs)
+applyValue funs (VGen i vs0) vs = VGen i (vs0++vs)
+applyValue funs (VSusp i env vs0 k) vs = VSusp i env vs0 (\v -> applyValue funs (k v) vs)
+applyValue funs (VClosure env (EAbs b x e)) (v:vs) = apply funs (v:env) e vs
+applyValue funs (VImplArg _) vs = error "implicit argument in function position"
+
+-----------------------------------------------------
+-- Pattern matching
+-----------------------------------------------------
+
+match :: Funs -> CId -> [Equation] -> [Value] -> [Value] -> Value
+match funs f eqs as0 vs0 =
+ case eqs of
+ [] -> VApp f (as0++vs0)
+ (Equ ps res):eqs -> tryMatches eqs ps as0 res []
+ where
+ tryMatches eqs [] [] res env = apply funs env res vs0
+ tryMatches eqs (p:ps) (a:as) res env = tryMatch p a env
+ where
+ tryMatch (PVar x ) (v ) env = tryMatches eqs ps as res (v:env)
+ tryMatch (PWild ) (_ ) env = tryMatches eqs ps as res env
+ tryMatch (p ) (VMeta i envi vs ) env = VSusp i envi vs (\v -> tryMatch p v env)
+ tryMatch (p ) (VGen i vs ) env = VApp f (as0++vs0)
+ tryMatch (p ) (VSusp i envi vs k) env = VSusp i envi vs (\v -> tryMatch p (k v) env)
+ tryMatch (PApp f1 ps1) (VApp f2 vs2 ) env | f1 == f2 = tryMatches eqs (ps1++ps) (vs2++as) res env
+ tryMatch (PLit l1 ) (VLit l2 ) env | l1 == l2 = tryMatches eqs ps as res env
+ tryMatch (PImplArg p ) (VImplArg v ) env = tryMatch p v env
+ tryMatch _ _ env = match funs f eqs as0 vs0
+
diff --git a/src/runtime/haskell/PGF/Expr.hs-boot b/src/runtime/haskell/PGF/Expr.hs-boot new file mode 100644 index 000000000..34a62a410 --- /dev/null +++ b/src/runtime/haskell/PGF/Expr.hs-boot @@ -0,0 +1,28 @@ +module PGF.Expr where
+
+import PGF.CId
+import qualified Text.PrettyPrint as PP
+import qualified Text.ParserCombinators.ReadP as RP
+
+data Expr
+
+instance Eq Expr
+instance Ord Expr
+instance Show Expr
+
+
+data BindType = Explicit | Implicit
+
+instance Eq BindType
+instance Ord BindType
+instance Show BindType
+
+
+pArg :: RP.ReadP Expr
+pBinds :: RP.ReadP [(BindType,CId)]
+
+ppExpr :: Int -> [CId] -> Expr -> PP.Doc
+
+freshName :: CId -> [CId] -> CId
+
+ppParens :: Bool -> PP.Doc -> PP.Doc
diff --git a/src/runtime/haskell/PGF/Generate.hs b/src/runtime/haskell/PGF/Generate.hs new file mode 100644 index 000000000..5add00a78 --- /dev/null +++ b/src/runtime/haskell/PGF/Generate.hs @@ -0,0 +1,66 @@ +module PGF.Generate where + +import PGF.CId +import PGF.Data +import PGF.Macros +import PGF.TypeCheck + +import qualified Data.Map as M +import System.Random + +-- generate an infinite list of trees exhaustively +generate :: PGF -> Type -> Maybe Int -> [Expr] +generate pgf ty@(DTyp _ cat _) dp = filter (\e -> case checkExpr pgf e ty of + Left _ -> False + Right _ -> True ) + (concatMap (\i -> gener i cat) depths) + where + gener 0 c = [EFun f | (f, ([],_)) <- fns c] + gener i c = [ + tr | + (f, (cs,_)) <- fns c, + let alts = map (gener (i-1)) cs, + ts <- combinations alts, + let tr = foldl EApp (EFun f) ts, + depth tr >= i + ] + fns c = [(f,catSkeleton ty) | (f,ty) <- functionsToCat pgf c] + depths = maybe [0 ..] (\d -> [0..d]) dp + +-- generate an infinite list of trees randomly +genRandom :: StdGen -> PGF -> Type -> [Expr] +genRandom gen pgf ty@(DTyp _ cat _) = filter (\e -> case checkExpr pgf e ty of + Left _ -> False + Right _ -> True ) + (genTrees (randomRs (0.0, 1.0 :: Double) gen) cat) + where + timeout = 47 -- give up + + genTrees ds0 cat = + let (ds,ds2) = splitAt (timeout+1) ds0 -- for time out, else ds + (t,k) = genTree ds cat + in (if k>timeout then id else (t:)) + (genTrees ds2 cat) -- else (drop k ds) + + genTree rs = gett rs where + gett ds cid | cid == cidString = (ELit (LStr "foo"), 1) + gett ds cid | cid == cidInt = (ELit (LInt 12345), 1) + gett ds cid | cid == cidFloat = (ELit (LFlt 12345), 1) + gett [] _ = (ELit (LStr "TIMEOUT"), 1) ---- + gett ds cat = case fns cat of + [] -> (EMeta 0,1) + fs -> let + d:ds2 = ds + (f,args) = getf d fs + (ts,k) = getts ds2 args + in (foldl EApp (EFun f) ts, k+1) + getf d fs = let lg = (length fs) in + fs !! (floor (d * fromIntegral lg)) + getts ds cats = case cats of + c:cs -> let + (t, k) = gett ds c + (ts,ks) = getts (drop k ds) cs + in (t:ts, k + ks) + _ -> ([],0) + + fns cat = [(f,(fst (catSkeleton ty))) | (f,ty) <- functionsToCat pgf cat] diff --git a/src/runtime/haskell/PGF/Linearize.hs b/src/runtime/haskell/PGF/Linearize.hs new file mode 100644 index 000000000..fdd4cecb5 --- /dev/null +++ b/src/runtime/haskell/PGF/Linearize.hs @@ -0,0 +1,166 @@ +{-# LANGUAGE ParallelListComp #-} +module PGF.Linearize + (linearizes,realize,realizes,linTree, linTreeMark,linearizesMark) where + +import PGF.CId +import PGF.Data +import PGF.Macros +import PGF.Tree + +import Control.Monad +import qualified Data.Map as Map +import Data.List + +import Debug.Trace + +-- linearization and computation of concrete PGF Terms + +linearizes :: PGF -> CId -> Expr -> [String] +linearizes pgf lang = realizes . linTree pgf lang + +realize :: Term -> String +realize = concat . take 1 . realizes + +realizes :: Term -> [String] +realizes = map (unwords . untokn) . realizest + +realizest :: Term -> [[Tokn]] +realizest trm = case trm of + R ts -> realizest (ts !! 0) + S ss -> map concat $ combinations $ map realizest ss + K t -> [[t]] + W s t -> [[KS (s ++ r)] | [KS r] <- realizest t] + FV ts -> concatMap realizest ts + TM s -> [[KS s]] + _ -> [[KS $ "REALIZE_ERROR " ++ show trm]] ---- debug + +untokn :: [Tokn] -> [String] +untokn ts = case ts of + KP d _ : [] -> d + KP d vs : ws -> let ss@(s:_) = untokn ws in sel d vs s ++ ss + KS s : ws -> s : untokn ws + [] -> [] + where + sel d vs w = case [v | Alt v cs <- vs, any (\c -> isPrefixOf c w) cs] of + v:_ -> v + _ -> d + +-- Lifts all variants to the top level (except those in macros). +liftVariants :: Term -> [Term] +liftVariants = f + where + f (R ts) = liftM R $ mapM f ts + f (P t1 t2) = liftM2 P (f t1) (f t2) + f (S ts) = liftM S $ mapM f ts + f (FV ts) = ts >>= f + f (W s t) = liftM (W s) $ f t + f t = return t + +linTree :: PGF -> CId -> Expr -> Term +linTree pgf lang e = lin (expr2tree e) Nothing + where + cnc = lookMap (error "no lang") lang (concretes pgf) + + lin (Abs xs e ) mty = case lin e Nothing of + R ts -> R $ ts ++ (Data.List.map (kks . showCId . snd) xs) + TM s -> R $ (TM s) : (Data.List.map (kks . showCId . snd) xs) + lin (Fun fun es) mty = case Map.lookup fun (funs (abstract pgf)) of + Just (DTyp hyps _ _,_,_) -> let argVariants = sequence [liftVariants (lin e (Just ty)) | e <- es | (_,_,ty) <- hyps] + in variants [compute pgf lang args $ lookMap tm0 fun (lins cnc) | args <- argVariants] + Nothing -> tm0 + lin (Lit (LStr s)) mty = R [kks (show s)] -- quoted + lin (Lit (LInt i)) mty = R [kks (show i)] + lin (Lit (LFlt d)) mty = R [kks (show d)] + lin (Var x) mty = case mty of + Just (DTyp _ cat _) -> compute pgf lang [K (KS (showCId x))] (lookMap tm0 cat (lindefs cnc)) + Nothing -> TM (showCId x) + lin (Meta i) mty = case mty of + Just (DTyp _ cat _) -> compute pgf lang [K (KS (show i))] (lookMap tm0 cat (lindefs cnc)) + Nothing -> TM (show i) + +variants :: [Term] -> Term +variants ts = case ts of + [t] -> t + _ -> FV ts + +unvariants :: Term -> [Term] +unvariants t = case t of + FV ts -> ts + _ -> [t] + +compute :: PGF -> CId -> [Term] -> Term -> Term +compute pgf lang args = comp where + comp trm = case trm of + P r p -> proj (comp r) (comp p) + W s t -> W s (comp t) + R ts -> R $ map comp ts + V i -> idx args i -- already computed + F c -> comp $ look c -- not computed (if contains argvar) + FV ts -> FV $ map comp ts + S ts -> S $ filter (/= S []) $ map comp ts + _ -> trm + + look = lookOper pgf lang + + idx xs i = if i > length xs - 1 + then trace + ("too large " ++ show i ++ " for\n" ++ unlines (map show xs) ++ "\n") tm0 + else xs !! i + + proj r p = case (r,p) of + (_, FV ts) -> FV $ map (proj r) ts + (FV ts, _ ) -> FV $ map (\t -> proj t p) ts + (W s t, _) -> kks (s ++ getString (proj t p)) + _ -> comp $ getField r (getIndex p) + + getString t = case t of + K (KS s) -> s + _ -> error ("ERROR in grammar compiler: string from "++ show t) "ERR" + + getIndex t = case t of + C i -> i + TM _ -> 0 -- default value for parameter + _ -> trace ("ERROR in grammar compiler: index from " ++ show t) 666 + + getField t i = case t of + R rs -> idx rs i + TM s -> TM s + _ -> error ("ERROR in grammar compiler: field from " ++ show t) t + +--------- +-- markup with tree positions + +linearizesMark :: PGF -> CId -> Expr -> [String] +linearizesMark pgf lang = realizes . linTreeMark pgf lang + +linTreeMark :: PGF -> CId -> Expr -> Term +linTreeMark pgf lang = lin [] . expr2tree + where + lin p (Abs xs e ) = case lin p e of + R ts -> R $ ts ++ (Data.List.map (kks . showCId . snd) xs) + TM s -> R $ (TM s) : (Data.List.map (kks . showCId . snd) xs) + lin p (Fun fun es) = + let argVariants = + mapM (\ (i,e) -> liftVariants $ lin (sub p i) e) (zip [0..] es) + in variants [mark (fun,p) $ compute pgf lang args $ look fun | + args <- argVariants] + lin p (Lit (LStr s)) = mark p $ R [kks (show s)] -- quoted + lin p (Lit (LInt i)) = mark p $ R [kks (show i)] + lin p (Lit (LFlt d)) = mark p $ R [kks (show d)] + lin p (Var x) = mark p $ TM (showCId x) + lin p (Meta i) = mark p $ TM (show i) + + look = lookLin pgf lang + + mark :: Show a => a -> Term -> Term + mark p t = case t of + R ts -> R $ map (mark p) ts + FV ts -> R $ map (mark p) ts + S ts -> S $ bracket p ts + K s -> S $ bracket p [t] + W s (R ts) -> R [mark p $ kks (s ++ u) | K (KS u) <- ts] + _ -> t + -- otherwise in normal form + + bracket p ts = [kks ("("++show p)] ++ ts ++ [kks ")"] + sub p i = p ++ [i] diff --git a/src/runtime/haskell/PGF/Macros.hs b/src/runtime/haskell/PGF/Macros.hs new file mode 100644 index 000000000..af25de025 --- /dev/null +++ b/src/runtime/haskell/PGF/Macros.hs @@ -0,0 +1,154 @@ +module PGF.Macros where + +import PGF.CId +import PGF.Data +import Control.Monad +import qualified Data.Map as Map +import qualified Data.Array as Array +import Data.Maybe +import Data.List + +-- operations for manipulating PGF grammars and objects + +mapConcretes :: (Concr -> Concr) -> PGF -> PGF +mapConcretes f pgf = pgf { concretes = Map.map f (concretes pgf) } + +lookLin :: PGF -> CId -> CId -> Term +lookLin pgf lang fun = + lookMap tm0 fun $ lins $ lookMap (error "no lang") lang $ concretes pgf + +lookOper :: PGF -> CId -> CId -> Term +lookOper pgf lang fun = + lookMap tm0 fun $ opers $ lookMap (error "no lang") lang $ concretes pgf + +lookLincat :: PGF -> CId -> CId -> Term +lookLincat pgf lang fun = + lookMap tm0 fun $ lincats $ lookMap (error "no lang") lang $ concretes pgf + +lookParamLincat :: PGF -> CId -> CId -> Term +lookParamLincat pgf lang fun = + lookMap tm0 fun $ paramlincats $ lookMap (error "no lang") lang $ concretes pgf + +lookPrintName :: PGF -> CId -> CId -> Term +lookPrintName pgf lang fun = + lookMap tm0 fun $ printnames $ lookMap (error "no lang") lang $ concretes pgf + +lookType :: PGF -> CId -> Type +lookType pgf f = + case lookMap (error $ "lookType " ++ show f) f (funs (abstract pgf)) of + (ty,_,_) -> ty + +lookDef :: PGF -> CId -> [Equation] +lookDef pgf f = + case lookMap (error $ "lookDef " ++ show f) f (funs (abstract pgf)) of + (_,a,eqs) -> eqs + +isData :: PGF -> CId -> Bool +isData pgf f = + case Map.lookup f (funs (abstract pgf)) of + Just (_,_,[]) -> True -- the encoding of data constrs + _ -> False + +lookValCat :: PGF -> CId -> CId +lookValCat pgf = valCat . lookType pgf + +lookParser :: PGF -> CId -> Maybe ParserInfo +lookParser pgf lang = Map.lookup lang (concretes pgf) >>= parser + +lookStartCat :: PGF -> CId +lookStartCat pgf = mkCId $ fromMaybe "S" $ msum $ Data.List.map (Map.lookup (mkCId "startcat")) + [gflags pgf, aflags (abstract pgf)] + +lookGlobalFlag :: PGF -> CId -> String +lookGlobalFlag pgf f = + lookMap "?" f (gflags pgf) + +lookAbsFlag :: PGF -> CId -> String +lookAbsFlag pgf f = + lookMap "?" f (aflags (abstract pgf)) + +lookConcr :: PGF -> CId -> Concr +lookConcr pgf cnc = + lookMap (error $ "Missing concrete syntax: " ++ showCId cnc) cnc $ concretes pgf + +lookConcrFlag :: PGF -> CId -> CId -> Maybe String +lookConcrFlag pgf lang f = Map.lookup f $ cflags $ lookConcr pgf lang + +functionsToCat :: PGF -> CId -> [(CId,Type)] +functionsToCat pgf cat = + [(f,ty) | f <- fs, Just (ty,_,_) <- [Map.lookup f $ funs $ abstract pgf]] + where + fs = lookMap [] cat $ catfuns $ abstract pgf + +missingLins :: PGF -> CId -> [CId] +missingLins pgf lang = [c | c <- fs, not (hasl c)] where + fs = Map.keys $ funs $ abstract pgf + hasl = hasLin pgf lang + +hasLin :: PGF -> CId -> CId -> Bool +hasLin pgf lang f = Map.member f $ lins $ lookConcr pgf lang + +restrictPGF :: (CId -> Bool) -> PGF -> PGF +restrictPGF cond pgf = pgf { + abstract = abstr { + funs = restrict $ funs $ abstr, + cats = restrict $ cats $ abstr + } + } ---- restrict concrs also, might be needed + where + restrict = Map.filterWithKey (\c _ -> cond c) + abstr = abstract pgf + +depth :: Expr -> Int +depth (EAbs _ _ t) = depth t +depth (EApp e1 e2) = max (depth e1) (depth e2) + 1 +depth _ = 1 + +cftype :: [CId] -> CId -> Type +cftype args val = DTyp [(Explicit,wildCId,cftype [] arg) | arg <- args] val [] + +typeOfHypo :: Hypo -> Type +typeOfHypo (_,_,ty) = ty + +catSkeleton :: Type -> ([CId],CId) +catSkeleton ty = case ty of + DTyp hyps val _ -> ([valCat (typeOfHypo h) | h <- hyps],val) + +typeSkeleton :: Type -> ([(Int,CId)],CId) +typeSkeleton ty = case ty of + DTyp hyps val _ -> ([(contextLength ty, valCat ty) | h <- hyps, let ty = typeOfHypo h],val) + +valCat :: Type -> CId +valCat ty = case ty of + DTyp _ val _ -> val + +contextLength :: Type -> Int +contextLength ty = case ty of + DTyp hyps _ _ -> length hyps + +term0 :: CId -> Term +term0 = TM . showCId + +tm0 :: Term +tm0 = TM "?" + +kks :: String -> Term +kks = K . KS + +-- lookup with default value +lookMap :: (Show i, Ord i) => a -> i -> Map.Map i a -> a +lookMap d c m = Map.findWithDefault d c m + +--- from Operations +combinations :: [[a]] -> [[a]] +combinations t = case t of + [] -> [[]] + aa:uu -> [a:u | a <- aa, u <- combinations uu] + +isLiteralCat :: CId -> Bool +isLiteralCat = (`elem` [cidString, cidFloat, cidInt, cidVar]) + +cidString = mkCId "String" +cidInt = mkCId "Int" +cidFloat = mkCId "Float" +cidVar = mkCId "__gfVar" diff --git a/src/runtime/haskell/PGF/Morphology.hs b/src/runtime/haskell/PGF/Morphology.hs new file mode 100644 index 000000000..9eee71a97 --- /dev/null +++ b/src/runtime/haskell/PGF/Morphology.hs @@ -0,0 +1,26 @@ +module PGF.Morphology(Lemma,Analysis,Morpho, + buildMorpho, + lookupMorpho,fullFormLexicon) where + +import PGF.ShowLinearize (collectWords) +import PGF.Data +import PGF.CId + +import qualified Data.Map as Map +import Data.List (intersperse) + +-- these 4 definitions depend on the datastructure used + +type Lemma = CId +type Analysis = String + +newtype Morpho = Morpho (Map.Map String [(Lemma,Analysis)]) + +buildMorpho :: PGF -> Language -> Morpho +buildMorpho pgf lang = Morpho (Map.fromListWith (++) (collectWords pgf lang)) + +lookupMorpho :: Morpho -> String -> [(Lemma,Analysis)] +lookupMorpho (Morpho mo) s = maybe [] id $ Map.lookup s mo + +fullFormLexicon :: Morpho -> [(String,[(Lemma,Analysis)])] +fullFormLexicon (Morpho mo) = Map.toList mo diff --git a/src/runtime/haskell/PGF/PMCFG.hs b/src/runtime/haskell/PGF/PMCFG.hs new file mode 100644 index 000000000..c657e3d17 --- /dev/null +++ b/src/runtime/haskell/PGF/PMCFG.hs @@ -0,0 +1,119 @@ +module PGF.PMCFG where
+
+import PGF.CId
+import PGF.Expr
+
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+import qualified Data.IntMap as IntMap
+import Data.Array.IArray
+import Data.Array.Unboxed
+import Text.PrettyPrint
+
+type FCat = Int
+type FIndex = Int
+type FPointPos = Int
+data FSymbol
+ = FSymCat {-# UNPACK #-} !Int {-# UNPACK #-} !FIndex
+ | FSymLit {-# UNPACK #-} !Int {-# UNPACK #-} !FIndex
+ | FSymKS [String]
+ | FSymKP [String] [Alternative]
+ deriving (Eq,Ord,Show)
+type Profile = [Int]
+data Production
+ = FApply {-# UNPACK #-} !FunId [FCat]
+ | FCoerce {-# UNPACK #-} !FCat
+ | FConst Expr [String]
+ deriving (Eq,Ord,Show)
+data FFun = FFun CId [Profile] {-# UNPACK #-} !(UArray FIndex SeqId) deriving (Eq,Ord,Show)
+type FSeq = Array FPointPos FSymbol
+type FunId = Int
+type SeqId = Int
+
+data Alternative =
+ Alt [String] [String]
+ deriving (Eq,Ord,Show)
+
+data ParserInfo
+ = ParserInfo { functions :: Array FunId FFun
+ , sequences :: Array SeqId FSeq
+ , productions0:: IntMap.IntMap (Set.Set Production) -- this are the original productions as they are loaded from the PGF file
+ , productions :: IntMap.IntMap (Set.Set Production) -- this are the productions after the filtering for useless productions
+ , startCats :: Map.Map CId [FCat]
+ , totalCats :: {-# UNPACK #-} !FCat
+ }
+
+
+fcatString, fcatInt, fcatFloat, fcatVar :: Int
+fcatString = (-1)
+fcatInt = (-2)
+fcatFloat = (-3)
+fcatVar = (-4)
+
+isLiteralFCat :: FCat -> Bool
+isLiteralFCat = (`elem` [fcatString, fcatInt, fcatFloat, fcatVar])
+
+ppPMCFG :: ParserInfo -> Doc
+ppPMCFG pinfo =
+ text "productions" $$
+ nest 2 (vcat [ppProduction (fcat,prod) | (fcat,set) <- IntMap.toList (productions pinfo), prod <- Set.toList set]) $$
+ text "functions" $$
+ nest 2 (vcat (map ppFun (assocs (functions pinfo)))) $$
+ text "sequences" $$
+ nest 2 (vcat (map ppSeq (assocs (sequences pinfo)))) $$
+ text "startcats" $$
+ nest 2 (vcat (map ppStartCat (Map.toList (startCats pinfo))))
+
+ppProduction (fcat,FApply funid args) =
+ ppFCat fcat <+> text "->" <+> ppFunId funid <> brackets (hcat (punctuate comma (map ppFCat args)))
+ppProduction (fcat,FCoerce arg) =
+ ppFCat fcat <+> text "->" <+> char '_' <> brackets (ppFCat arg)
+ppProduction (fcat,FConst _ ss) =
+ ppFCat fcat <+> text "->" <+> ppStrs ss
+
+ppFun (funid,FFun fun _ arr) =
+ ppFunId funid <+> text ":=" <+> parens (hcat (punctuate comma (map ppSeqId (elems arr)))) <+> brackets (ppCId fun)
+
+ppSeq (seqid,seq) =
+ ppSeqId seqid <+> text ":=" <+> hsep (map ppSymbol (elems seq))
+
+ppStartCat (id,fcats) =
+ ppCId id <+> text ":=" <+> brackets (hcat (punctuate comma (map ppFCat fcats)))
+
+ppSymbol (FSymCat d r) = char '<' <> int d <> comma <> int r <> char '>'
+ppSymbol (FSymLit d r) = char '<' <> int d <> comma <> int r <> char '>'
+ppSymbol (FSymKS ts) = ppStrs ts
+ppSymbol (FSymKP ts alts) = text "pre" <+> braces (hsep (punctuate semi (ppStrs ts : map ppAlt alts)))
+
+ppAlt (Alt ts ps) = ppStrs ts <+> char '/' <+> hsep (map (doubleQuotes . text) ps)
+
+ppStrs ss = doubleQuotes (hsep (map text ss))
+
+ppFCat fcat
+ | fcat == fcatString = text "CString"
+ | fcat == fcatInt = text "CInt"
+ | fcat == fcatFloat = text "CFloat"
+ | fcat == fcatVar = text "CVar"
+ | otherwise = char 'C' <> int fcat
+
+ppFunId funid = char 'F' <> int funid
+ppSeqId seqid = char 'S' <> int seqid
+
+
+filterProductions = closure
+ where
+ closure prods0
+ | IntMap.size prods == IntMap.size prods0 = prods
+ | otherwise = closure prods
+ where
+ prods = IntMap.mapMaybe (filterProdSet prods0) prods0
+
+ filterProdSet prods set0
+ | Set.null set = Nothing
+ | otherwise = Just set
+ where
+ set = Set.filter (filterRule prods) set0
+
+ filterRule prods (FApply funid args) = all (\fcat -> isLiteralFCat fcat || IntMap.member fcat prods) args
+ filterRule prods (FCoerce fcat) = isLiteralFCat fcat || IntMap.member fcat prods
+ filterRule prods _ = True
diff --git a/src/runtime/haskell/PGF/Paraphrase.hs b/src/runtime/haskell/PGF/Paraphrase.hs new file mode 100644 index 000000000..58d15b2e8 --- /dev/null +++ b/src/runtime/haskell/PGF/Paraphrase.hs @@ -0,0 +1,112 @@ +---------------------------------------------------------------------- +-- | +-- Module : Paraphrase +-- Maintainer : AR +-- Stability : (stable) +-- Portability : (portable) +-- +-- Generate parapharases with def definitions. +----------------------------------------------------------------------------- + +module PGF.Paraphrase ( + paraphrase, + paraphraseN + ) where + +import PGF.Data +import PGF.Tree +import PGF.Macros (lookDef,isData) +import PGF.CId + +import Data.List (nub,sort,group) +import qualified Data.Map as Map + +import Debug.Trace ---- + +paraphrase :: PGF -> Expr -> [Expr] +paraphrase pgf = nub . paraphraseN 2 pgf + +paraphraseN :: Int -> PGF -> Expr -> [Expr] +paraphraseN i pgf = map tree2expr . paraphraseN' i pgf . expr2tree + +paraphraseN' :: Int -> PGF -> Tree -> [Tree] +paraphraseN' 0 _ t = [t] +paraphraseN' i pgf t = + step i t ++ [Fun g ts' | Fun g ts <- step (i-1) t, ts' <- sequence (map par ts)] + where + par = paraphraseN' (i-1) pgf + step 0 t = [t] + step i t = let stept = step (i-1) t in stept ++ concat [def u | u <- stept] + def = fromDef pgf + +fromDef :: PGF -> Tree -> [Tree] +fromDef pgf t@(Fun f ts) = defDown t ++ defUp t where + defDown t = [subst g u | let equ = equsFrom f, (u,g) <- match equ ts, trequ "U" f equ] + defUp t = [subst g u | equ <- equsTo f, (u,g) <- match [equ] ts, trequ "D" f equ] + + equsFrom f = [(ps,d) | Just equs <- [lookup f equss], (Fun _ ps,d) <- equs] + + equsTo f = [c | (_,equs) <- equss, c <- casesTo f equs] + + casesTo f equs = + [(ps,p) | (p,d@(Fun g ps)) <- equs, g==f, + isClosed d || (length equs == 1 && isLinear d)] + + equss = [(f,[(Fun f (map patt2tree ps), expr2tree d) | (Equ ps d) <- eqs]) | + (f,(_,_,eqs)) <- Map.assocs (funs (abstract pgf)), not (null eqs)] + + trequ s f e = True ----trace (s ++ ": " ++ show f ++ " " ++ show e) True + +subst :: Subst -> Tree -> Tree +subst g e = case e of + Fun f ts -> Fun f (map substg ts) + Var x -> maybe e id $ lookup x g + _ -> e + where + substg = subst g + +type Subst = [(CId,Tree)] + +-- this applies to pattern, hence don't need to consider abstractions +isClosed :: Tree -> Bool +isClosed t = case t of + Fun _ ts -> all isClosed ts + Var _ -> False + _ -> True + +-- this applies to pattern, hence don't need to consider abstractions +isLinear :: Tree -> Bool +isLinear = nodup . vars where + vars t = case t of + Fun _ ts -> concatMap vars ts + Var x -> [x] + _ -> [] + nodup = all ((<2) . length) . group . sort + + +match :: [([Tree],Tree)] -> [Tree] -> [(Tree, Subst)] +match cases terms = case cases of + [] -> [] + (patts,_):_ | length patts /= length terms -> [] + (patts,val):cc -> case mapM tryMatch (zip patts terms) of + Just substs -> return (val, concat substs) + _ -> match cc terms + where + tryMatch (p,t) = case (p, t) of + (Var x, _) | notMeta t -> return [(x,t)] + (Fun p pp, Fun f tt) | p == f && length pp == length tt -> do + matches <- mapM tryMatch (zip pp tt) + return (concat matches) + _ -> if p==t then return [] else Nothing + + notMeta e = case e of + Meta _ -> False + Fun f ts -> all notMeta ts + _ -> True + +-- | Converts a pattern to tree. +patt2tree :: Patt -> Tree +patt2tree (PApp f ps) = Fun f (map patt2tree ps) +patt2tree (PLit l) = Lit l +patt2tree (PVar x) = Var x +patt2tree PWild = Meta 0 diff --git a/src/runtime/haskell/PGF/Parsing/FCFG/Active.hs b/src/runtime/haskell/PGF/Parsing/FCFG/Active.hs new file mode 100644 index 000000000..e88926f6e --- /dev/null +++ b/src/runtime/haskell/PGF/Parsing/FCFG/Active.hs @@ -0,0 +1,205 @@ +---------------------------------------------------------------------- +-- | +-- Maintainer : Krasimir Angelov +-- Stability : (stable) +-- Portability : (portable) +-- +-- MCFG parsing, the active algorithm +----------------------------------------------------------------------------- + +module PGF.Parsing.FCFG.Active (parse) where + +import GF.Data.Assoc +import GF.Data.SortedList +import GF.Data.Utilities +import qualified GF.Data.MultiMap as MM + +import PGF.CId +import PGF.Data +import PGF.Tree +import PGF.Parsing.FCFG.Utilities +import PGF.BuildParser + +import Control.Monad (guard) + +import qualified Data.List as List +import qualified Data.Map as Map +import qualified Data.IntMap as IntMap +import qualified Data.Set as Set +import Data.Array.IArray +import Debug.Trace + +---------------------------------------------------------------------- +-- * parsing + +type FToken = String + +makeFinalEdge cat 0 0 = (cat, [EmptyRange]) +makeFinalEdge cat i j = (cat, [makeRange i j]) + +-- | the list of categories = possible starting categories +parse :: String -> ParserInfo -> Type -> [FToken] -> [Expr] +parse strategy pinfo (DTyp _ start _) toks = map (tree2expr) . nubsort $ filteredForests >>= forest2trees + where + inTokens = input toks + starts = Map.findWithDefault [] start (startCats pinfo) + schart = xchart2syntaxchart chart pinfo + (i,j) = inputBounds inTokens + finalEdges = [makeFinalEdge cat i j | cat <- starts] + forests = chart2forests schart (const False) finalEdges + filteredForests = forests >>= applyProfileToForest + + pinfoex = buildParserInfo pinfo + + chart = process strategy pinfo pinfoex inTokens axioms emptyXChart + axioms | isBU strategy = literals pinfoex inTokens ++ initialBU pinfo pinfoex inTokens + | isTD strategy = literals pinfoex inTokens ++ initialTD pinfo starts inTokens + +isBU s = s=="b" +isTD s = s=="t" + +-- used in prediction +emptyChildren :: FunId -> [FCat] -> SyntaxNode FunId RangeRec +emptyChildren ruleid args = SNode ruleid (replicate (length args) []) + + +process :: String -> ParserInfo -> ParserInfoEx -> Input FToken -> [Item] -> XChart FCat -> XChart FCat +process strategy pinfo pinfoex toks [] chart = chart +process strategy pinfo pinfoex toks (item:items) chart = process strategy pinfo pinfoex toks items $! univRule item chart + where + univRule item@(Active found rng lbl ppos node@(SNode ruleid recs) args cat) chart + | inRange (bounds lin) ppos = + case lin ! ppos of + FSymCat d r -> let c = args !! d + in case recs !! d of + [] -> case insertXChart chart item c of + Nothing -> chart + Just chart -> let items = do item@(Final found' _ _ _) <- lookupXChartFinal chart c + rng <- concatRange rng (found' !! r) + return (Active found rng lbl (ppos+1) (SNode ruleid (updateNth (const found') d recs)) args cat) + ++ + do guard (isTD strategy) + (ruleid,args) <- topdownRules pinfo c + return (Active [] EmptyRange 0 0 (emptyChildren ruleid args) args c) + in process strategy pinfo pinfoex toks items chart + found' -> let items = do rng <- concatRange rng (found' !! r) + return (Active found rng lbl (ppos+1) node args cat) + in process strategy pinfo pinfoex toks items chart + FSymKS [tok] + -> let items = do t_rng <- inputToken toks ? tok + rng' <- concatRange rng t_rng + return (Active found rng' lbl (ppos+1) node args cat) + in process strategy pinfo pinfoex toks items chart + | otherwise = + if inRange (bounds lins) (lbl+1) + then univRule (Active (rng:found) EmptyRange (lbl+1) 0 node args cat) chart + else univRule (Final (reverse (rng:found)) node args cat) chart + where + (FFun _ _ lins) = functions pinfo ! ruleid + lin = sequences pinfo ! (lins ! lbl) + univRule item@(Final found' node args cat) chart = + case insertXChart chart item cat of + Nothing -> chart + Just chart -> let items = do (Active found rng l ppos node@(SNode ruleid _) args c) <- lookupXChartAct chart cat + let FFun _ _ lins = functions pinfo ! ruleid + FSymCat d r = (sequences pinfo ! (lins ! l)) ! ppos + rng <- concatRange rng (found' !! r) + return (Active found rng l (ppos+1) (updateChildren node d found') args c) + ++ + do guard (isBU strategy) + (ruleid,args,c) <- leftcornerCats pinfoex ? cat + let FFun _ _ lins = functions pinfo ! ruleid + FSymCat d r = (sequences pinfo ! (lins ! 0)) ! 0 + return (Active [] (found' !! r) 0 1 (updateChildren (emptyChildren ruleid args) d found') args c) + + updateChildren :: SyntaxNode FunId RangeRec -> Int -> RangeRec -> SyntaxNode FunId RangeRec + updateChildren (SNode ruleid recs) i rec = SNode ruleid $! updateNth (const rec) i recs + in process strategy pinfo pinfoex toks items chart + +---------------------------------------------------------------------- +-- * XChart + +data Item + = Active RangeRec + Range + {-# UNPACK #-} !FIndex + {-# UNPACK #-} !FPointPos + (SyntaxNode FunId RangeRec) + [FCat] + FCat + | Final RangeRec (SyntaxNode FunId RangeRec) [FCat] FCat + deriving (Eq, Ord, Show) + +data XChart c = XChart !(MM.MultiMap c Item) !(MM.MultiMap c Item) + +emptyXChart :: Ord c => XChart c +emptyXChart = XChart MM.empty MM.empty + +insertXChart (XChart actives finals) item@(Active _ _ _ _ _ _ _) c = + case MM.insert' c item actives of + Nothing -> Nothing + Just actives -> Just (XChart actives finals) + +insertXChart (XChart actives finals) item@(Final _ _ _ _) c = + case MM.insert' c item finals of + Nothing -> Nothing + Just finals -> Just (XChart actives finals) + +lookupXChartAct (XChart actives finals) c = actives MM.! c +lookupXChartFinal (XChart actives finals) c = finals MM.! c + +xchart2syntaxchart :: XChart FCat -> ParserInfo -> SyntaxChart (CId,[Profile]) (FCat,RangeRec) +xchart2syntaxchart (XChart actives finals) pinfo = + accumAssoc groupSyntaxNodes $ + [ case node of + SNode ruleid rrecs -> let FFun fun prof _ = functions pinfo ! ruleid + in ((cat,found), SNode (fun,prof) (zip rhs rrecs)) + SString s -> ((cat,found), SString s) + SInt n -> ((cat,found), SInt n) + SFloat f -> ((cat,found), SFloat f) + | (Final found node rhs cat) <- MM.elems finals + ] + +literals :: ParserInfoEx -> Input FToken -> [Item] +literals pinfoex toks = + [let (c,node) = lexer t in (Final [rng] node [] c) | (t,rngs) <- aAssocs (inputToken toks), rng <- rngs, not (t `elem` grammarToks pinfoex)] + where + lexer t = + case reads t of + [(n,"")] -> (fcatInt, SInt (n::Integer)) + _ -> case reads t of + [(f,"")] -> (fcatFloat, SFloat (f::Double)) + _ -> (fcatString,SString t) + + +---------------------------------------------------------------------- +-- Earley -- + +-- called with all starting categories +initialTD :: ParserInfo -> [FCat] -> Input FToken -> [Item] +initialTD pinfo starts toks = + do cat <- starts + (ruleid,args) <- topdownRules pinfo cat + return (Active [] (Range 0 0) 0 0 (emptyChildren ruleid args) args cat) + +topdownRules pinfo cat = f cat [] + where + f cat rules = maybe rules (Set.fold g rules) (IntMap.lookup cat (productions pinfo)) + + g (FApply ruleid args) rules = (ruleid,args) : rules + g (FCoerce cat) rules = f cat rules + + +---------------------------------------------------------------------- +-- Kilbury -- + +initialBU :: ParserInfo -> ParserInfoEx -> Input FToken -> [Item] +initialBU pinfo pinfoex toks = + do (tok,rngs) <- aAssocs (inputToken toks) + (ruleid,args,cat) <- leftcornerTokens pinfoex ? tok + rng <- rngs + return (Active [] rng 0 1 (emptyChildren ruleid args) args cat) + ++ + do (ruleid,args,cat) <- epsilonRules pinfoex + let FFun _ _ _ = functions pinfo ! ruleid + return (Active [] EmptyRange 0 0 (emptyChildren ruleid args) args cat) diff --git a/src/runtime/haskell/PGF/Parsing/FCFG/Incremental.hs b/src/runtime/haskell/PGF/Parsing/FCFG/Incremental.hs new file mode 100644 index 000000000..296a0d33b --- /dev/null +++ b/src/runtime/haskell/PGF/Parsing/FCFG/Incremental.hs @@ -0,0 +1,371 @@ +{-# LANGUAGE BangPatterns #-}
+module PGF.Parsing.FCFG.Incremental
+ ( ParseState
+ , ErrorState
+ , initState
+ , nextState
+ , getCompletions
+ , recoveryStates
+ , extractTrees
+ , parse
+ , parseWithRecovery
+ ) where
+
+import Data.Array.IArray
+import Data.Array.Base (unsafeAt)
+import Data.List (isPrefixOf, foldl')
+import Data.Maybe (fromMaybe, maybe)
+import qualified Data.Map as Map
+import qualified GF.Data.TrieMap as TMap
+import qualified Data.IntMap as IntMap
+import qualified Data.Set as Set
+import Control.Monad
+
+import GF.Data.SortedList
+import PGF.CId
+import PGF.Data
+import PGF.Expr(Tree)
+import PGF.Macros
+import PGF.TypeCheck
+import Debug.Trace
+
+parse :: PGF -> Language -> Type -> [String] -> [Tree]
+parse pgf lang typ toks = loop (initState pgf lang typ) toks
+ where
+ loop ps [] = extractTrees ps typ
+ loop ps (t:ts) = case nextState ps t of
+ Left es -> []
+ Right ps -> loop ps ts
+
+parseWithRecovery :: PGF -> Language -> Type -> [Type] -> [String] -> [Tree]
+parseWithRecovery pgf lang typ open_typs toks = accept (initState pgf lang typ) toks
+ where
+ accept ps [] = extractTrees ps typ
+ accept ps (t:ts) =
+ case nextState ps t of
+ Right ps -> accept ps ts
+ Left es -> skip (recoveryStates open_typs es) ts
+
+ skip ps_map [] = extractTrees (fst ps_map) typ
+ skip ps_map (t:ts) =
+ case Map.lookup t (snd ps_map) of
+ Just ps -> accept ps ts
+ Nothing -> skip ps_map ts
+
+-- | Creates an initial parsing state for a given language and
+-- startup category.
+initState :: PGF -> Language -> Type -> ParseState
+initState pgf lang (DTyp _ start _) =
+ let items = do
+ cat <- fromMaybe [] (Map.lookup start (startCats pinfo))
+ (funid,args) <- foldForest (\funid args -> (:) (funid,args)) (\_ _ args -> args)
+ [] cat (productions pinfo)
+ let FFun fn _ lins = functions pinfo ! funid
+ (lbl,seqid) <- assocs lins
+ return (Active 0 0 funid seqid args (AK cat lbl))
+
+ pinfo =
+ case lookParser pgf lang of
+ Just pinfo -> pinfo
+ _ -> error ("Unknown language: " ++ showCId lang)
+
+ in PState pgf
+ pinfo
+ (Chart emptyAC [] emptyPC (productions pinfo) (totalCats pinfo) 0)
+ (TMap.singleton [] (Set.fromList items))
+
+-- | From the current state and the next token
+-- 'nextState' computes a new state, where the token
+-- is consumed and the current position is shifted by one.
+-- If the new token cannot be accepted then an error state
+-- is returned.
+nextState :: ParseState -> String -> Either ErrorState ParseState
+nextState (PState pgf pinfo chart items) t =
+ let (mb_agenda,map_items) = TMap.decompose items
+ agenda = maybe [] Set.toList mb_agenda
+ acc = fromMaybe TMap.empty (Map.lookup t map_items)
+ (acc1,chart1) = process (Just t) add (sequences pinfo) (functions pinfo) agenda acc chart
+ chart2 = chart1{ active =emptyAC
+ , actives=active chart1 : actives chart1
+ , passive=emptyPC
+ , offset =offset chart1+1
+ }
+ in if TMap.null acc1
+ then Left (EState pgf pinfo chart2)
+ else Right (PState pgf pinfo chart2 acc1)
+ where
+ add (tok:toks) item acc
+ | tok == t = TMap.insertWith Set.union toks (Set.singleton item) acc
+ add _ item acc = acc
+
+-- | If the next token is not known but only its prefix (possible empty prefix)
+-- then the 'getCompletions' function can be used to calculate the possible
+-- next words and the consequent states. This is used for word completions in
+-- the GF interpreter.
+getCompletions :: ParseState -> String -> Map.Map String ParseState
+getCompletions (PState pgf pinfo chart items) w =
+ let (mb_agenda,map_items) = TMap.decompose items
+ agenda = maybe [] Set.toList mb_agenda
+ acc = Map.filterWithKey (\tok _ -> isPrefixOf w tok) map_items
+ (acc',chart1) = process Nothing add (sequences pinfo) (functions pinfo) agenda acc chart
+ chart2 = chart1{ active =emptyAC
+ , actives=active chart1 : actives chart1
+ , passive=emptyPC
+ , offset =offset chart1+1
+ }
+ in fmap (PState pgf pinfo chart2) acc'
+ where
+ add (tok:toks) item acc
+ | isPrefixOf w tok = Map.insertWith (TMap.unionWith Set.union) tok (TMap.singleton toks (Set.singleton item)) acc
+ add _ item acc = acc
+
+recoveryStates :: [Type] -> ErrorState -> (ParseState, Map.Map String ParseState)
+recoveryStates open_types (EState pgf pinfo chart) =
+ let open_fcats = concatMap type2fcats open_types
+ agenda = foldl (complete open_fcats) [] (actives chart)
+ (acc,chart1) = process Nothing add (sequences pinfo) (functions pinfo) agenda Map.empty chart
+ chart2 = chart1{ active =emptyAC
+ , actives=active chart1 : actives chart1
+ , passive=emptyPC
+ , offset =offset chart1+1
+ }
+ in (PState pgf pinfo chart (TMap.singleton [] (Set.fromList agenda)), fmap (PState pgf pinfo chart2) acc)
+ where
+ type2fcats (DTyp _ cat _) = fromMaybe [] (Map.lookup cat (startCats pinfo))
+
+ complete open_fcats items ac =
+ foldl (Set.fold (\(Active j' ppos funid seqid args keyc) ->
+ (:) (Active j' (ppos+1) funid seqid args keyc)))
+ items
+ [set | fcat <- open_fcats, set <- lookupACByFCat fcat ac]
+
+ add (tok:toks) item acc = Map.insertWith (TMap.unionWith Set.union) tok (TMap.singleton toks (Set.singleton item)) acc
+
+-- | This function extracts the list of all completed parse trees
+-- that spans the whole input consumed so far. The trees are also
+-- limited by the category specified, which is usually
+-- the same as the startup category.
+extractTrees :: ParseState -> Type -> [Tree]
+extractTrees (PState pgf pinfo chart items) ty@(DTyp _ start _) =
+ nubsort [e1 | e <- exps, Right e1 <- [checkExpr pgf e ty]]
+ where
+ (mb_agenda,acc) = TMap.decompose items
+ agenda = maybe [] Set.toList mb_agenda
+ (_,st) = process Nothing (\_ _ -> id) (sequences pinfo) (functions pinfo) agenda () chart
+
+ exps = do
+ cat <- fromMaybe [] (Map.lookup start (startCats pinfo))
+ (funid,args) <- foldForest (\funid args -> (:) (funid,args)) (\_ _ args -> args)
+ [] cat (productions pinfo)
+ let FFun fn _ lins = functions pinfo ! funid
+ lbl <- indices lins
+ Just fid <- [lookupPC (PK cat lbl 0) (passive st)]
+ (fvs,tree) <- go Set.empty 0 (0,fid)
+ guard (Set.null fvs)
+ return tree
+
+ go rec fcat' (d,fcat)
+ | fcat < totalCats pinfo = return (Set.empty,EMeta (fcat'*10+d)) -- FIXME: here we assume that every rule has at most 10 arguments
+ | Set.member fcat rec = mzero
+ | otherwise = foldForest (\funid args trees ->
+ do let FFun fn _ lins = functions pinfo ! funid
+ args <- mapM (go (Set.insert fcat rec) fcat) (zip [0..] args)
+ check_ho_fun fn args
+ `mplus`
+ trees)
+ (\const _ trees ->
+ return (freeVar const,const)
+ `mplus`
+ trees)
+ [] fcat (forest st)
+
+ check_ho_fun fun args
+ | fun == _V = return (head args)
+ | fun == _B = return (foldl1 Set.difference (map fst args), foldr (\x e -> EAbs Explicit (mkVar (snd x)) e) (snd (head args)) (tail args))
+ | otherwise = return (Set.unions (map fst args),foldl (\e x -> EApp e (snd x)) (EFun fun) args)
+
+ mkVar (EFun v) = v
+ mkVar (EMeta _) = wildCId
+
+ freeVar (EFun v) = Set.singleton v
+ freeVar _ = Set.empty
+
+_B = mkCId "_B"
+_V = mkCId "_V"
+
+process mbt fn !seqs !funs [] acc chart = (acc,chart)
+process mbt fn !seqs !funs (item@(Active j ppos funid seqid args key0):items) acc chart
+ | inRange (bounds lin) ppos =
+ case unsafeAt lin ppos of
+ FSymCat d r -> let !fid = args !! d
+ key = AK fid r
+
+ items2 = case lookupPC (mkPK key k) (passive chart) of
+ Nothing -> items
+ Just id -> (Active j (ppos+1) funid seqid (updateAt d id args) key0) : items
+ items3 = foldForest (\funid args items -> Active k 0 funid (rhs funid r) args key : items)
+ (\_ _ items -> items)
+ items2 fid (forest chart)
+ in case lookupAC key (active chart) of
+ Nothing -> process mbt fn seqs funs items3 acc chart{active=insertAC key (Set.singleton item) (active chart)}
+ Just set | Set.member item set -> process mbt fn seqs funs items acc chart
+ | otherwise -> process mbt fn seqs funs items2 acc chart{active=insertAC key (Set.insert item set) (active chart)}
+ FSymKS toks -> let !acc' = fn toks (Active j (ppos+1) funid seqid args key0) acc
+ in process mbt fn seqs funs items acc' chart
+ FSymKP strs vars
+ -> let !acc' = foldl (\acc toks -> fn toks (Active j (ppos+1) funid seqid args key0) acc) acc
+ (strs:[strs' | Alt strs' _ <- vars])
+ in process mbt fn seqs funs items acc' chart
+ FSymLit d r -> let !fid = args !! d
+ in case [ts | FConst _ ts <- maybe [] Set.toList (IntMap.lookup fid (forest chart))] of
+ (toks:_) -> let !acc' = fn toks (Active j (ppos+1) funid seqid args key0) acc
+ in process mbt fn seqs funs items acc' chart
+ [] -> case litCatMatch fid mbt of
+ Just (toks,lit) -> let fid' = nextId chart
+ !acc' = fn toks (Active j (ppos+1) funid seqid (updateAt d fid' args) key0) acc
+ in process mbt fn seqs funs items acc' chart{forest=IntMap.insert fid' (Set.singleton (FConst lit toks)) (forest chart)
+ ,nextId=nextId chart+1
+ }
+ Nothing -> process mbt fn seqs funs items acc chart
+ | otherwise =
+ case lookupPC (mkPK key0 j) (passive chart) of
+ Nothing -> let fid = nextId chart
+
+ items2 = case lookupAC key0 ((active chart:actives chart) !! (k-j)) of
+ Nothing -> items
+ Just set -> Set.fold (\(Active j' ppos funid seqid args keyc) ->
+ let FSymCat d _ = unsafeAt (unsafeAt seqs seqid) ppos
+ in (:) (Active j' (ppos+1) funid seqid (updateAt d fid args) keyc)) items set
+ in process mbt fn seqs funs items2 acc chart{passive=insertPC (mkPK key0 j) fid (passive chart)
+ ,forest =IntMap.insert fid (Set.singleton (FApply funid args)) (forest chart)
+ ,nextId =nextId chart+1
+ }
+ Just id -> let items2 = [Active k 0 funid (rhs funid r) args (AK id r) | r <- labelsAC id (active chart)] ++ items
+ in process mbt fn seqs funs items2 acc chart{forest = IntMap.insertWith Set.union id (Set.singleton (FApply funid args)) (forest chart)}
+ where
+ !lin = unsafeAt seqs seqid
+ !k = offset chart
+
+ mkPK (AK fid lbl) j = PK fid lbl j
+
+ rhs funid lbl = unsafeAt lins lbl
+ where
+ FFun _ _ lins = unsafeAt funs funid
+
+
+updateAt :: Int -> a -> [a] -> [a]
+updateAt nr x xs = [if i == nr then x else y | (i,y) <- zip [0..] xs]
+
+litCatMatch fcat (Just t)
+ | fcat == fcatString = Just ([t],ELit (LStr t))
+ | fcat == fcatInt = case reads t of {[(n,"")] -> Just ([t],ELit (LInt n));
+ _ -> Nothing }
+ | fcat == fcatFloat = case reads t of {[(d,"")] -> Just ([t],ELit (LFlt d));
+ _ -> Nothing }
+ | fcat == fcatVar = Just ([t],EFun (mkCId t))
+litCatMatch _ _ = Nothing
+
+
+----------------------------------------------------------------
+-- Active Chart
+----------------------------------------------------------------
+
+data Active
+ = Active {-# UNPACK #-} !Int
+ {-# UNPACK #-} !FPointPos
+ {-# UNPACK #-} !FunId
+ {-# UNPACK #-} !SeqId
+ [FCat]
+ {-# UNPACK #-} !ActiveKey
+ deriving (Eq,Show,Ord)
+data ActiveKey
+ = AK {-# UNPACK #-} !FCat
+ {-# UNPACK #-} !FIndex
+ deriving (Eq,Ord,Show)
+type ActiveChart = IntMap.IntMap (IntMap.IntMap (Set.Set Active))
+
+emptyAC :: ActiveChart
+emptyAC = IntMap.empty
+
+lookupAC :: ActiveKey -> ActiveChart -> Maybe (Set.Set Active)
+lookupAC (AK fcat l) chart = IntMap.lookup fcat chart >>= IntMap.lookup l
+
+lookupACByFCat :: FCat -> ActiveChart -> [Set.Set Active]
+lookupACByFCat fcat chart =
+ case IntMap.lookup fcat chart of
+ Nothing -> []
+ Just map -> IntMap.elems map
+
+labelsAC :: FCat -> ActiveChart -> [FIndex]
+labelsAC fcat chart =
+ case IntMap.lookup fcat chart of
+ Nothing -> []
+ Just map -> IntMap.keys map
+
+insertAC :: ActiveKey -> Set.Set Active -> ActiveChart -> ActiveChart
+insertAC (AK fcat l) set chart = IntMap.insertWith IntMap.union fcat (IntMap.singleton l set) chart
+
+
+----------------------------------------------------------------
+-- Passive Chart
+----------------------------------------------------------------
+
+data PassiveKey
+ = PK {-# UNPACK #-} !FCat
+ {-# UNPACK #-} !FIndex
+ {-# UNPACK #-} !Int
+ deriving (Eq,Ord,Show)
+
+type PassiveChart = Map.Map PassiveKey FCat
+
+emptyPC :: PassiveChart
+emptyPC = Map.empty
+
+lookupPC :: PassiveKey -> PassiveChart -> Maybe FCat
+lookupPC key chart = Map.lookup key chart
+
+insertPC :: PassiveKey -> FCat -> PassiveChart -> PassiveChart
+insertPC key fcat chart = Map.insert key fcat chart
+
+
+----------------------------------------------------------------
+-- Forest
+----------------------------------------------------------------
+
+foldForest :: (FunId -> [FCat] -> b -> b) -> (Expr -> [String] -> b -> b) -> b -> FCat -> IntMap.IntMap (Set.Set Production) -> b
+foldForest f g b fcat forest =
+ case IntMap.lookup fcat forest of
+ Nothing -> b
+ Just set -> Set.fold foldProd b set
+ where
+ foldProd (FCoerce fcat) b = foldForest f g b fcat forest
+ foldProd (FApply funid args) b = f funid args b
+ foldProd (FConst const toks) b = g const toks b
+
+
+----------------------------------------------------------------
+-- Parse State
+----------------------------------------------------------------
+
+-- | An abstract data type whose values represent
+-- the current state in an incremental parser.
+data ParseState = PState PGF ParserInfo Chart (TMap.TrieMap String (Set.Set Active))
+
+data Chart
+ = Chart
+ { active :: ActiveChart
+ , actives :: [ActiveChart]
+ , passive :: PassiveChart
+ , forest :: IntMap.IntMap (Set.Set Production)
+ , nextId :: {-# UNPACK #-} !FCat
+ , offset :: {-# UNPACK #-} !Int
+ }
+ deriving Show
+
+----------------------------------------------------------------
+-- Error State
+----------------------------------------------------------------
+
+-- | An abstract data type whose values represent
+-- the state in an incremental parser after an error.
+data ErrorState = EState PGF ParserInfo Chart
diff --git a/src/runtime/haskell/PGF/Parsing/FCFG/Utilities.hs b/src/runtime/haskell/PGF/Parsing/FCFG/Utilities.hs new file mode 100644 index 000000000..dc0b2dc4a --- /dev/null +++ b/src/runtime/haskell/PGF/Parsing/FCFG/Utilities.hs @@ -0,0 +1,188 @@ +---------------------------------------------------------------------- +-- | +-- Maintainer : PL +-- Stability : (stable) +-- Portability : (portable) +-- +-- > CVS $Date: 2005/05/13 12:40:19 $ +-- > CVS $Author: peb $ +-- > CVS $Revision: 1.6 $ +-- +-- Basic type declarations and functions for grammar formalisms +----------------------------------------------------------------------------- + + +module PGF.Parsing.FCFG.Utilities where + +import Control.Monad +import Data.Array +import Data.List (groupBy) + +import PGF.CId +import PGF.Data +import PGF.Tree +import GF.Data.Assoc +import GF.Data.Utilities (sameLength, foldMerge, splitBy) + + +------------------------------------------------------------ +-- ranges as single pairs + +type RangeRec = [Range] + +data Range = Range {-# UNPACK #-} !Int {-# UNPACK #-} !Int + | EmptyRange + deriving (Eq, Ord, Show) + +makeRange :: Int -> Int -> Range +makeRange = Range + +concatRange :: Range -> Range -> [Range] +concatRange EmptyRange rng = return rng +concatRange rng EmptyRange = return rng +concatRange (Range i j) (Range j' k) = [Range i k | j==j'] + +minRange :: Range -> Int +minRange (Range i j) = i + +maxRange :: Range -> Int +maxRange (Range i j) = j + + +------------------------------------------------------------ +-- * representaions of input tokens + +data Input t = MkInput { inputBounds :: (Int, Int), + inputToken :: Assoc t [Range] + } + +input :: Ord t => [t] -> Input t +input toks = MkInput inBounds inToken + where + inBounds = (0, length toks) + inToken = accumAssoc id [ (tok, makeRange i j) | (i,j,tok) <- zip3 [0..] [1..] toks ] + +inputMany :: Ord t => [[t]] -> Input t +inputMany toks = MkInput inBounds inToken + where + inBounds = (0, length toks) + inToken = accumAssoc id [ (tok, makeRange i j) | (i,j,ts) <- zip3 [0..] [1..] toks, tok <- ts ] + + +------------------------------------------------------------ +-- * representations of syntactical analyses + +-- ** charts as finite maps over edges + +-- | The values of the chart, a list of key-daughters pairs, +-- has unique keys. In essence, it is a map from 'n' to daughters. +-- The daughters should be a set (not necessarily sorted) of rhs's. +type SyntaxChart n e = Assoc e [SyntaxNode n [e]] + +data SyntaxNode n e = SMeta + | SNode n [e] + | SString String + | SInt Integer + | SFloat Double + deriving (Eq,Ord,Show) + +groupSyntaxNodes :: Ord n => [SyntaxNode n e] -> [SyntaxNode n [e]] +groupSyntaxNodes [] = [] +groupSyntaxNodes (SNode n0 es0:xs) = (SNode n0 (es0:ess)) : groupSyntaxNodes xs' + where + (ess,xs') = span xs + + span [] = ([],[]) + span xs@(SNode n es:xs') + | n0 == n = let (ess,xs) = span xs' in (es:ess,xs) + | otherwise = ([],xs) +groupSyntaxNodes (SString s:xs) = (SString s) : groupSyntaxNodes xs +groupSyntaxNodes (SInt n:xs) = (SInt n) : groupSyntaxNodes xs +groupSyntaxNodes (SFloat f:xs) = (SFloat f) : groupSyntaxNodes xs + +-- ** syntax forests + +data SyntaxForest n = FMeta + | FNode n [[SyntaxForest n]] + -- ^ The outer list should be a set (not necessarily sorted) + -- of possible alternatives. Ie. the outer list + -- is a disjunctive node, and the inner lists + -- are (conjunctive) concatenative nodes + | FString String + | FInt Integer + | FFloat Double + deriving (Eq, Ord, Show) + +instance Functor SyntaxForest where + fmap f (FNode n forests) = FNode (f n) $ map (map (fmap f)) forests + fmap _ (FString s) = FString s + fmap _ (FInt n) = FInt n + fmap _ (FFloat f) = FFloat f + fmap _ (FMeta) = FMeta + +forestName :: SyntaxForest n -> Maybe n +forestName (FNode n _) = Just n +forestName _ = Nothing + +unifyManyForests :: (Monad m, Eq n) => [SyntaxForest n] -> m (SyntaxForest n) +unifyManyForests = foldM unifyForests FMeta + +-- | two forests can be unified, if either is 'FMeta', or both have the same parent, +-- and all children can be unified +unifyForests :: (Monad m, Eq n) => SyntaxForest n -> SyntaxForest n -> m (SyntaxForest n) +unifyForests FMeta forest = return forest +unifyForests forest FMeta = return forest +unifyForests (FNode name1 children1) (FNode name2 children2) + | name1 == name2 && not (null children) = return $ FNode name1 children + where children = [ forests | forests1 <- children1, forests2 <- children2, + sameLength forests1 forests2, + forests <- zipWithM unifyForests forests1 forests2 ] +unifyForests (FString s1) (FString s2) + | s1 == s2 = return $ FString s1 +unifyForests (FInt n1) (FInt n2) + | n1 == n2 = return $ FInt n1 +unifyForests (FFloat f1) (FFloat f2) + | f1 == f2 = return $ FFloat f1 +unifyForests _ _ = fail "forest unification failure" + + +-- ** conversions between representations + +chart2forests :: (Ord n, Ord e) => + SyntaxChart n e -- ^ The complete chart + -> (e -> Bool) -- ^ When is an edge 'FMeta'? + -> [e] -- ^ The starting edges + -> [SyntaxForest n] -- ^ The result has unique keys, ie. all 'n' are joined together. + -- In essence, the result is a map from 'n' to forest daughters +chart2forests chart isMeta = concatMap (edge2forests []) + where edge2forests edges edge + | isMeta edge = [FMeta] + | edge `elem` edges = [] + | otherwise = map (item2forest (edge:edges)) $ chart ? edge + item2forest edges (SMeta) = FMeta + item2forest edges (SNode name children) = + FNode name $ children >>= mapM (edge2forests edges) + item2forest edges (SString s) = FString s + item2forest edges (SInt n) = FInt n + item2forest edges (SFloat f) = FFloat f + + +applyProfileToForest :: SyntaxForest (CId,[Profile]) -> [SyntaxForest CId] +applyProfileToForest (FNode (fun,profiles) children) + | fun == wildCId = concat chForests + | otherwise = [ FNode fun chForests | not (null chForests) ] + where chForests = concat [ mapM (unifyManyForests . map (forests !!)) profiles | + forests0 <- children, + forests <- mapM applyProfileToForest forests0 ] +applyProfileToForest (FString s) = [FString s] +applyProfileToForest (FInt n) = [FInt n] +applyProfileToForest (FFloat f) = [FFloat f] +applyProfileToForest (FMeta) = [FMeta] + + +forest2trees :: SyntaxForest CId -> [Tree] +forest2trees (FNode n forests) = map (Fun n) $ forests >>= mapM forest2trees +forest2trees (FString s) = [Lit (LStr s)] +forest2trees (FInt n) = [Lit (LInt n)] +forest2trees (FFloat f) = [Lit (LFlt f)] +forest2trees (FMeta) = [Meta 0] diff --git a/src/runtime/haskell/PGF/ShowLinearize.hs b/src/runtime/haskell/PGF/ShowLinearize.hs new file mode 100644 index 000000000..dd3b997a6 --- /dev/null +++ b/src/runtime/haskell/PGF/ShowLinearize.hs @@ -0,0 +1,113 @@ +module PGF.ShowLinearize ( + collectWords, + tableLinearize, + recordLinearize, + termLinearize, + tabularLinearize, + allLinearize, + markLinearize + ) where + +import PGF.CId +import PGF.Data +import PGF.Tree +import PGF.Macros +import PGF.Linearize + +import GF.Data.Operations +import Data.List +import qualified Data.Map as Map + +-- printing linearizations in different ways with source parameters + +-- internal representation, only used internally in this module +data Record = + RR [(String,Record)] + | RT [(String,Record)] + | RFV [Record] + | RS String + | RCon String + +prRecord :: Record -> String +prRecord = prr where + prr t = case t of + RR fs -> concat $ + "{" : + (intersperse ";" (map (\ (l,v) -> unwords [l,"=", prr v]) fs)) ++ ["}"] + RT fs -> concat $ + "table {" : + (intersperse ";" (map (\ (l,v) -> unwords [l,"=>",prr v]) fs)) ++ ["}"] + RFV ts -> concat $ + "variants {" : (intersperse ";" (map prr ts)) ++ ["}"] + RS s -> prQuotedString s + RCon s -> s + +-- uses the encoding of record types in PGF.paramlincat +mkRecord :: Term -> Term -> Record +mkRecord typ trm = case (typ,trm) of + (_, FV ts) -> RFV $ map (mkRecord typ) ts + (R rs, R ts) -> RR [(str lab, mkRecord ty t) | (P lab ty, t) <- zip rs ts] + (S [FV ps,ty],R ts) -> RT [(str par, mkRecord ty t) | (par, t) <- zip ps ts] + (_,W s (R ts)) -> mkRecord typ (R [K (KS (s ++ u)) | K (KS u) <- ts]) + (FV ps, C i) -> RCon $ str $ ps !! i + (S [], _) -> case realizes trm of + [s] -> RS s + ss -> RFV $ map RS ss + _ -> RS $ show trm ---- printTree trm + where + str = realize + +-- show all branches, without labels and params +allLinearize :: (String -> String) -> PGF -> CId -> Expr -> String +allLinearize unlex pgf lang = concat . map (unlex . pr) . tabularLinearize pgf lang where + pr (p,vs) = unlines vs + +-- show all branches, with labels and params +tableLinearize :: (String -> String) -> PGF -> CId -> Expr -> String +tableLinearize unlex pgf lang = unlines . map pr . tabularLinearize pgf lang where + pr (p,vs) = p +++ ":" +++ unwords (intersperse "|" (map unlex vs)) + +-- create a table from labels+params to variants +tabularLinearize :: PGF -> CId -> Expr -> [(String,[String])] +tabularLinearize pgf lang = branches . recLinearize pgf lang where + branches r = case r of + RR fs -> [(lab +++ b,s) | (lab,t) <- fs, (b,s) <- branches t] + RT fs -> [(lab +++ b,s) | (lab,t) <- fs, (b,s) <- branches t] + RFV rs -> concatMap branches rs + RS s -> [([], [s])] + RCon _ -> [] + +-- show record in GF-source-like syntax +recordLinearize :: PGF -> CId -> Expr -> String +recordLinearize pgf lang = prRecord . recLinearize pgf lang + +-- create a GF-like record, forming the basis of all functions above +recLinearize :: PGF -> CId -> Expr -> Record +recLinearize pgf lang tree = mkRecord typ $ linTree pgf lang tree where + typ = case expr2tree tree of + Fun f _ -> lookParamLincat pgf lang $ valCat $ lookType pgf f + +-- show PGF term +termLinearize :: PGF -> CId -> Expr -> String +termLinearize pgf lang = show . linTree pgf lang + +-- show bracketed markup with references to tree structure +markLinearize :: PGF -> CId -> Expr -> String +markLinearize pgf lang = concat . take 1 . linearizesMark pgf lang + + +-- for Morphology: word, lemma, tags +collectWords :: PGF -> Language -> [(String, [(CId,String)])] +collectWords pgf lang = + concatMap collOne + [(f,c,0) | (f,(DTyp [] c _,_,_)) <- Map.toList $ funs $ abstract pgf] + where + collOne (f,c,i) = + fromRec f [showCId c] (recLinearize pgf lang (foldl EApp (EFun f) (replicate i (EMeta 888)))) + fromRec f v r = case r of + RR rs -> concat [fromRec f v t | (_,t) <- rs] + RT rs -> concat [fromRec f (p:v) t | (p,t) <- rs] + RFV rs -> concatMap (fromRec f v) rs + RS s -> [(s,[(f,unwords (reverse v))])] + RCon c -> [] ---- inherent + diff --git a/src/runtime/haskell/PGF/Tree.hs b/src/runtime/haskell/PGF/Tree.hs new file mode 100644 index 000000000..cb2052cd7 --- /dev/null +++ b/src/runtime/haskell/PGF/Tree.hs @@ -0,0 +1,71 @@ +module PGF.Tree + ( Tree(..), + tree2expr, expr2tree, + prTree + ) where + +import PGF.CId +import PGF.Expr hiding (Tree) + +import Data.Char +import Data.List as List +import Control.Monad +import qualified Text.PrettyPrint as PP +import qualified Text.ParserCombinators.ReadP as RP + +-- | The tree is an evaluated expression in the abstract syntax +-- of the grammar. The type is especially restricted to not +-- allow unapplied lambda abstractions. The tree is used directly +-- from the linearizer and is produced directly from the parser. +data Tree = + Abs [(BindType,CId)] Tree -- ^ lambda abstraction. The list of variables is non-empty + | Var CId -- ^ variable + | Fun CId [Tree] -- ^ function application + | Lit Literal -- ^ literal + | Meta {-# UNPACK #-} !MetaId -- ^ meta variable + deriving (Eq, Ord) + +----------------------------------------------------- +-- Conversion Expr <-> Tree +----------------------------------------------------- + +-- | Converts a tree to expression. The conversion +-- is always total, every tree is a valid expression. +tree2expr :: Tree -> Expr +tree2expr = tree2expr [] + where + tree2expr ys (Fun x ts) = foldl EApp (EFun x) (List.map (tree2expr ys) ts) + tree2expr ys (Lit l) = ELit l + tree2expr ys (Meta n) = EMeta n + tree2expr ys (Abs xs t) = foldr (\(b,x) e -> EAbs b x e) (tree2expr (List.map snd (reverse xs)++ys) t) xs + tree2expr ys (Var x) = case List.lookup x (zip ys [0..]) of + Just i -> EVar i + Nothing -> error "unknown variable" + +-- | Converts an expression to tree. The conversion is only partial. +-- Variables and meta variables of function type and beta redexes are not allowed. +expr2tree :: Expr -> Tree +expr2tree e = abs [] [] e + where + abs ys xs (EAbs b x e) = abs ys ((b,x):xs) e + abs ys xs (ETyped e _) = abs ys xs e + abs ys xs e = case xs of + [] -> app ys [] e + xs -> Abs (reverse xs) (app (map snd xs++ys) [] e) + + app xs as (EApp e1 e2) = app xs ((abs xs [] e2) : as) e1 + app xs as (ELit l) + | List.null as = Lit l + | otherwise = error "literal of function type encountered" + app xs as (EMeta n) + | List.null as = Meta n + | otherwise = error "meta variables of function type are not allowed in trees" + app xs as (EAbs _ x e) = error "beta redexes are not allowed in trees" + app xs as (EVar i) = Var (xs !! i) + app xs as (EFun f) = Fun f as + app xs as (ETyped e _) = app xs as e + + +prTree :: Tree -> String +prTree = showExpr [] . tree2expr + diff --git a/src/runtime/haskell/PGF/Type.hs b/src/runtime/haskell/PGF/Type.hs new file mode 100644 index 000000000..013754a45 --- /dev/null +++ b/src/runtime/haskell/PGF/Type.hs @@ -0,0 +1,103 @@ +module PGF.Type ( Type(..), Hypo,
+ readType, showType,
+ mkType, mkHypo, mkDepHypo, mkImplHypo,
+ pType, ppType, ppHypo ) where
+
+import PGF.CId
+import {-# SOURCE #-} PGF.Expr
+import Data.Char
+import Data.List
+import qualified Text.PrettyPrint as PP
+import qualified Text.ParserCombinators.ReadP as RP
+import Control.Monad
+
+-- | To read a type from a 'String', use 'readType'.
+data Type =
+ DTyp [Hypo] CId [Expr]
+ deriving (Eq,Ord,Show)
+
+-- | 'Hypo' represents a hypothesis in a type i.e. in the type A -> B, A is the hypothesis
+type Hypo = (BindType,CId,Type)
+
+-- | Reads a 'Type' from a 'String'.
+readType :: String -> Maybe Type
+readType s = case [x | (x,cs) <- RP.readP_to_S pType s, all isSpace cs] of
+ [x] -> Just x
+ _ -> Nothing
+
+-- | renders type as 'String'. The list
+-- of identifiers is the list of all free variables
+-- in the expression in order reverse to the order
+-- of binding.
+showType :: [CId] -> Type -> String
+showType vars = PP.render . ppType 0 vars
+
+-- | creates a type from list of hypothesises, category and
+-- list of arguments for the category. The operation
+-- @mkType [h_1,...,h_n] C [e_1,...,e_m]@ will create
+-- @h_1 -> ... -> h_n -> C e_1 ... e_m@
+mkType :: [Hypo] -> CId -> [Expr] -> Type
+mkType hyps cat args = DTyp hyps cat args
+
+-- | creates hypothesis for non-dependent type i.e. A
+mkHypo :: Type -> Hypo
+mkHypo ty = (Explicit,wildCId,ty)
+
+-- | creates hypothesis for dependent type i.e. (x : A)
+mkDepHypo :: CId -> Type -> Hypo
+mkDepHypo x ty = (Explicit,x,ty)
+
+-- | creates hypothesis for dependent type with implicit argument i.e. ({x} : A)
+mkImplHypo :: CId -> Type -> Hypo
+mkImplHypo x ty = (Implicit,x,ty)
+
+pType :: RP.ReadP Type
+pType = do
+ RP.skipSpaces
+ hyps <- RP.sepBy (pHypo >>= \h -> RP.skipSpaces >> RP.string "->" >> return h) RP.skipSpaces
+ RP.skipSpaces
+ (cat,args) <- pAtom
+ return (DTyp (concat hyps) cat args)
+ where
+ pHypo =
+ do (cat,args) <- pAtom
+ return [(Explicit,wildCId,DTyp [] cat args)]
+ RP.<++
+ (RP.between (RP.char '(') (RP.char ')') $ do
+ xs <- RP.option [(Explicit,wildCId)] $ do
+ xs <- pBinds
+ RP.skipSpaces
+ RP.char ':'
+ return xs
+ ty <- pType
+ return [(b,v,ty) | (b,v) <- xs])
+ RP.<++
+ (RP.between (RP.char '{') (RP.char '}') $ do
+ vs <- RP.sepBy1 (RP.skipSpaces >> pCId) (RP.skipSpaces >> RP.char ',')
+ RP.skipSpaces
+ RP.char ':'
+ ty <- pType
+ return [(Implicit,v,ty) | v <- vs])
+
+ pAtom = do
+ cat <- pCId
+ RP.skipSpaces
+ args <- RP.sepBy pArg RP.skipSpaces
+ return (cat, args)
+
+ppType :: Int -> [CId] -> Type -> PP.Doc
+ppType d scope (DTyp hyps cat args)
+ | null hyps = ppRes scope cat args
+ | otherwise = let (scope',hdocs) = mapAccumL ppHypo scope hyps
+ in ppParens (d > 0) (foldr (\hdoc doc -> hdoc PP.<+> PP.text "->" PP.<+> doc) (ppRes scope' cat args) hdocs)
+ where
+ ppRes scope cat es = ppCId cat PP.<+> PP.hsep (map (ppExpr 4 scope) es)
+
+ppHypo scope (Explicit,x,typ) = if x == wildCId
+ then (scope,ppType 1 scope typ)
+ else let y = freshName x scope
+ in (y:scope,PP.parens (ppCId y PP.<+> PP.char ':' PP.<+> ppType 0 scope typ))
+ppHypo scope (Implicit,x,typ) = if x == wildCId
+ then (scope,PP.parens (PP.braces (ppCId x) PP.<+> PP.char ':' PP.<+> ppType 0 scope typ))
+ else let y = freshName x scope
+ in (y:scope,PP.parens (PP.braces (ppCId y) PP.<+> PP.char ':' PP.<+> ppType 0 scope typ))
diff --git a/src/runtime/haskell/PGF/TypeCheck.hs b/src/runtime/haskell/PGF/TypeCheck.hs new file mode 100644 index 000000000..937c21786 --- /dev/null +++ b/src/runtime/haskell/PGF/TypeCheck.hs @@ -0,0 +1,524 @@ +---------------------------------------------------------------------- +-- | +-- Module : PGF.TypeCheck +-- Maintainer : Krasimir Angelov +-- Stability : (stable) +-- Portability : (portable) +-- +-- Type checking in abstract syntax with dependent types. +-- The type checker also performs renaming and checking for unknown +-- functions. The variable references are replaced by de Bruijn indices. +-- +----------------------------------------------------------------------------- + +module PGF.TypeCheck (checkType, checkExpr, inferExpr, + + ppTcError, TcError(..) + ) where + +import PGF.Data +import PGF.Expr +import PGF.Macros (typeOfHypo) +import PGF.CId + +import Data.Map as Map +import Data.IntMap as IntMap +import Data.Maybe as Maybe +import Data.List as List +import Control.Monad +import Text.PrettyPrint + +----------------------------------------------------- +-- The Scope +----------------------------------------------------- + +data TType = TTyp Env Type +newtype Scope = Scope [(CId,TType)] + +emptyScope = Scope [] + +addScopedVar :: CId -> TType -> Scope -> Scope +addScopedVar x tty (Scope gamma) = Scope ((x,tty):gamma) + +-- | returns the type and the De Bruijn index of a local variable +lookupVar :: CId -> Scope -> Maybe (Int,TType) +lookupVar x (Scope gamma) = listToMaybe [(i,tty) | ((y,tty),i) <- zip gamma [0..], x == y] + +-- | returns the type and the name of a local variable +getVar :: Int -> Scope -> (CId,TType) +getVar i (Scope gamma) = gamma !! i + +scopeEnv :: Scope -> Env +scopeEnv (Scope gamma) = let n = length gamma + in [VGen (n-i-1) [] | i <- [0..n-1]] + +scopeVars :: Scope -> [CId] +scopeVars (Scope gamma) = List.map fst gamma + +scopeSize :: Scope -> Int +scopeSize (Scope gamma) = length gamma + +----------------------------------------------------- +-- The Monad +----------------------------------------------------- + +type MetaStore = IntMap MetaValue +data MetaValue + = MUnbound Scope [Expr -> TcM ()] + | MBound Expr + | MGuarded Expr [Expr -> TcM ()] {-# UNPACK #-} !Int -- the Int is the number of constraints that have to be solved + -- to unlock this meta variable + +newtype TcM a = TcM {unTcM :: Abstr -> MetaId -> MetaStore -> TcResult a} +data TcResult a + = Ok {-# UNPACK #-} !MetaId MetaStore a + | Fail TcError + +instance Monad TcM where + return x = TcM (\abstr metaid ms -> Ok metaid ms x) + f >>= g = TcM (\abstr metaid ms -> case unTcM f abstr metaid ms of + Ok metaid ms x -> unTcM (g x) abstr metaid ms + Fail e -> Fail e) + +instance Functor TcM where + fmap f x = TcM (\abstr metaid ms -> case unTcM x abstr metaid ms of + Ok metaid ms x -> Ok metaid ms (f x) + Fail e -> Fail e) + +lookupCatHyps :: CId -> TcM [Hypo] +lookupCatHyps cat = TcM (\abstr metaid ms -> case Map.lookup cat (cats abstr) of + Just hyps -> Ok metaid ms hyps + Nothing -> Fail (UnknownCat cat)) + +lookupFunType :: CId -> TcM TType +lookupFunType fun = TcM (\abstr metaid ms -> case Map.lookup fun (funs abstr) of + Just (ty,_,_) -> Ok metaid ms (TTyp [] ty) + Nothing -> Fail (UnknownFun fun)) + +newMeta :: Scope -> TcM MetaId +newMeta scope = TcM (\abstr metaid ms -> Ok (metaid+1) (IntMap.insert metaid (MUnbound scope []) ms) metaid) + +newGuardedMeta :: Scope -> Expr -> TcM MetaId +newGuardedMeta scope e = getFuns >>= \funs -> TcM (\abstr metaid ms -> Ok (metaid+1) (IntMap.insert metaid (MGuarded e [] 0) ms) metaid) + +getMeta :: MetaId -> TcM MetaValue +getMeta i = TcM (\abstr metaid ms -> Ok metaid ms $! case IntMap.lookup i ms of + Just mv -> mv) +setMeta :: MetaId -> MetaValue -> TcM () +setMeta i mv = TcM (\abstr metaid ms -> Ok metaid (IntMap.insert i mv ms) ()) + +tcError :: TcError -> TcM a +tcError e = TcM (\abstr metaid ms -> Fail e) + +getFuns :: TcM Funs +getFuns = TcM (\abstr metaid ms -> Ok metaid ms (funs abstr)) + +addConstraint :: MetaId -> MetaId -> Env -> [Value] -> (Value -> TcM ()) -> TcM () +addConstraint i j env vs c = do + funs <- getFuns + mv <- getMeta j + case mv of + MUnbound scope cs -> addRef >> setMeta j (MUnbound scope ((\e -> release >> c (apply funs env e vs)) : cs)) + MBound e -> c (apply funs env e vs) + MGuarded e cs x | x == 0 -> c (apply funs env e vs) + | otherwise -> addRef >> setMeta j (MGuarded e ((\e -> release >> c (apply funs env e vs)) : cs) x) + where + addRef = TcM (\abstr metaid ms -> case IntMap.lookup i ms of + Just (MGuarded e cs x) -> Ok metaid (IntMap.insert i (MGuarded e cs (x+1)) ms) ()) + + release = TcM (\abstr metaid ms -> case IntMap.lookup i ms of + Just (MGuarded e cs x) -> if x == 1 + then unTcM (sequence_ [c e | c <- cs]) abstr metaid (IntMap.insert i (MGuarded e [] 0) ms) + else Ok metaid (IntMap.insert i (MGuarded e cs (x-1)) ms) ()) + +----------------------------------------------------- +-- Type errors +----------------------------------------------------- + +-- | If an error occurs in the typechecking phase +-- the type checker returns not a plain text error message +-- but a 'TcError' structure which describes the error. +data TcError + = UnknownCat CId -- ^ Unknown category name was found. + | UnknownFun CId -- ^ Unknown function name was found. + | WrongCatArgs [CId] Type CId Int Int -- ^ A category was applied to wrong number of arguments. + -- The first integer is the number of expected arguments and + -- the second the number of given arguments. + -- The @[CId]@ argument is the list of free variables + -- in the type. It should be used for the 'showType' function. + | TypeMismatch [CId] Expr Type Type -- ^ The expression is not of the expected type. + -- The first type is the expected type, while + -- the second is the inferred. The @[CId]@ argument is the list + -- of free variables in both the expression and the type. + -- It should be used for the 'showType' and 'showExpr' functions. + | NotFunType [CId] Expr Type -- ^ Something that is not of function type was applied to an argument. + | CannotInferType [CId] Expr -- ^ It is not possible to infer the type of an expression. + | UnresolvedMetaVars [CId] Expr [MetaId] -- ^ Some metavariables have to be instantiated in order to complete the typechecking. + | UnexpectedImplArg [CId] Expr -- ^ Implicit argument was passed where the type doesn't allow it + +-- | Renders the type checking error to a document. See 'Text.PrettyPrint'. +ppTcError :: TcError -> Doc +ppTcError (UnknownCat cat) = text "Category" <+> ppCId cat <+> text "is not in scope" +ppTcError (UnknownFun fun) = text "Function" <+> ppCId fun <+> text "is not in scope" +ppTcError (WrongCatArgs xs ty cat m n) = text "Category" <+> ppCId cat <+> text "should have" <+> int m <+> text "argument(s), but has been given" <+> int n $$ + text "In the type:" <+> ppType 0 xs ty +ppTcError (TypeMismatch xs e ty1 ty2) = text "Couldn't match expected type" <+> ppType 0 xs ty1 $$ + text " against inferred type" <+> ppType 0 xs ty2 $$ + text "In the expression:" <+> ppExpr 0 xs e +ppTcError (NotFunType xs e ty) = text "A function type is expected for the expression" <+> ppExpr 0 xs e <+> text "instead of type" <+> ppType 0 xs ty +ppTcError (CannotInferType xs e) = text "Cannot infer the type of expression" <+> ppExpr 0 xs e +ppTcError (UnresolvedMetaVars xs e ms) = text "Meta variable(s)" <+> fsep (List.map ppMeta ms) <+> text "should be resolved" $$ + text "in the expression:" <+> ppExpr 0 xs e +ppTcError (UnexpectedImplArg xs e) = braces (ppExpr 0 xs e) <+> text "is implicit argument but not implicit argument is expected here" + +----------------------------------------------------- +-- checkType +----------------------------------------------------- + +-- | Check whether a given type is consistent with the abstract +-- syntax of the grammar. +checkType :: PGF -> Type -> Either TcError Type +checkType pgf ty = + case unTcM (tcType emptyScope ty >>= refineType) (abstract pgf) 0 IntMap.empty of + Ok _ ms ty -> Right ty + Fail err -> Left err + +tcType :: Scope -> Type -> TcM Type +tcType scope ty@(DTyp hyps cat es) = do + (scope,hyps) <- tcHypos scope hyps + c_hyps <- lookupCatHyps cat + let m = length es + n = length [ty | (Explicit,x,ty) <- c_hyps] + (delta,es) <- tcCatArgs scope es [] c_hyps ty n m + return (DTyp hyps cat es) + +tcHypos :: Scope -> [Hypo] -> TcM (Scope,[Hypo]) +tcHypos scope [] = return (scope,[]) +tcHypos scope (h:hs) = do + (scope,h ) <- tcHypo scope h + (scope,hs) <- tcHypos scope hs + return (scope,h:hs) + +tcHypo :: Scope -> Hypo -> TcM (Scope,Hypo) +tcHypo scope (b,x,ty) = do + ty <- tcType scope ty + if x == wildCId + then return (scope,(b,x,ty)) + else return (addScopedVar x (TTyp (scopeEnv scope) ty) scope,(b,x,ty)) + +tcCatArgs scope [] delta [] ty0 n m = return (delta,[]) +tcCatArgs scope (EImplArg e:es) delta ((Explicit,x,ty):hs) ty0 n m = tcError (UnexpectedImplArg (scopeVars scope) e) +tcCatArgs scope (EImplArg e:es) delta ((Implicit,x,ty):hs) ty0 n m = do + e <- tcExpr scope e (TTyp delta ty) + funs <- getFuns + (delta,es) <- if x == wildCId + then tcCatArgs scope es delta hs ty0 n m + else tcCatArgs scope es (eval funs (scopeEnv scope) e:delta) hs ty0 n m + return (delta,EImplArg e:es) +tcCatArgs scope es delta ((Implicit,x,ty):hs) ty0 n m = do + i <- newMeta scope + (delta,es) <- if x == wildCId + then tcCatArgs scope es delta hs ty0 n m + else tcCatArgs scope es (VMeta i (scopeEnv scope) [] : delta) hs ty0 n m + return (delta,EImplArg (EMeta i) : es) +tcCatArgs scope (e:es) delta ((Explicit,x,ty):hs) ty0 n m = do + e <- tcExpr scope e (TTyp delta ty) + funs <- getFuns + (delta,es) <- if x == wildCId + then tcCatArgs scope es delta hs ty0 n m + else tcCatArgs scope es (eval funs (scopeEnv scope) e:delta) hs ty0 n m + return (delta,e:es) +tcCatArgs scope _ delta _ ty0@(DTyp _ cat _) n m = do + tcError (WrongCatArgs (scopeVars scope) ty0 cat n m) + +----------------------------------------------------- +-- checkExpr +----------------------------------------------------- + +-- | Checks an expression against a specified type. +checkExpr :: PGF -> Expr -> Type -> Either TcError Expr +checkExpr pgf e ty = + case unTcM (do e <- tcExpr emptyScope e (TTyp [] ty) + e <- refineExpr e + checkResolvedMetaStore emptyScope e + return e) (abstract pgf) 0 IntMap.empty of + Ok _ ms e -> Right e + Fail err -> Left err + +tcExpr :: Scope -> Expr -> TType -> TcM Expr +tcExpr scope e0@(EAbs Implicit x e) tty = + case tty of + TTyp delta (DTyp ((Implicit,y,ty):hs) c es) -> do e <- if y == wildCId + then tcExpr (addScopedVar x (TTyp delta ty) scope) + e (TTyp delta (DTyp hs c es)) + else tcExpr (addScopedVar x (TTyp delta ty) scope) + e (TTyp ((VGen (scopeSize scope) []):delta) (DTyp hs c es)) + return (EAbs Implicit x e) + _ -> do ty <- evalType (scopeSize scope) tty + tcError (NotFunType (scopeVars scope) e0 ty) +tcExpr scope e0 (TTyp delta (DTyp ((Implicit,y,ty):hs) c es)) = do + e0 <- if y == wildCId + then tcExpr (addScopedVar wildCId (TTyp delta ty) scope) + e0 (TTyp delta (DTyp hs c es)) + else tcExpr (addScopedVar wildCId (TTyp delta ty) scope) + e0 (TTyp ((VGen (scopeSize scope) []):delta) (DTyp hs c es)) + return (EAbs Implicit wildCId e0) +tcExpr scope e0@(EAbs Explicit x e) tty = + case tty of + TTyp delta (DTyp ((Explicit,y,ty):hs) c es) -> do e <- if y == wildCId + then tcExpr (addScopedVar x (TTyp delta ty) scope) + e (TTyp delta (DTyp hs c es)) + else tcExpr (addScopedVar x (TTyp delta ty) scope) + e (TTyp ((VGen (scopeSize scope) []):delta) (DTyp hs c es)) + return (EAbs Explicit x e) + _ -> do ty <- evalType (scopeSize scope) tty + tcError (NotFunType (scopeVars scope) e0 ty) +tcExpr scope (EMeta _) tty = do + i <- newMeta scope + return (EMeta i) +tcExpr scope e0 tty = do + (e0,tty0) <- infExpr scope e0 + i <- newGuardedMeta scope e0 + eqType scope (scopeSize scope) i tty tty0 + return (EMeta i) + + +----------------------------------------------------- +-- inferExpr +----------------------------------------------------- + +-- | Tries to infer the type of a given expression. Note that +-- even if the expression is type correct it is not always +-- possible to infer its type in the GF type system. +-- In this case the function returns the 'CannotInferType' error. +inferExpr :: PGF -> Expr -> Either TcError (Expr,Type) +inferExpr pgf e = + case unTcM (do (e,tty) <- infExpr emptyScope e + e <- refineExpr e + checkResolvedMetaStore emptyScope e + ty <- evalType 0 tty + return (e,ty)) (abstract pgf) 1 IntMap.empty of + Ok _ ms (e,ty) -> Right (e,ty) + Fail err -> Left err + +infExpr :: Scope -> Expr -> TcM (Expr,TType) +infExpr scope e0@(EApp e1 e2) = do + (e1,TTyp delta ty) <- infExpr scope e1 + (e0,delta,ty) <- tcArg scope e1 e2 delta ty + return (e0,TTyp delta ty) +infExpr scope e0@(EFun x) = do + case lookupVar x scope of + Just (i,tty) -> return (EVar i,tty) + Nothing -> do tty <- lookupFunType x + return (e0,tty) +infExpr scope e0@(EVar i) = do + return (e0,snd (getVar i scope)) +infExpr scope e0@(ELit l) = do + let cat = case l of + LStr _ -> mkCId "String" + LInt _ -> mkCId "Int" + LFlt _ -> mkCId "Float" + return (e0,TTyp [] (DTyp [] cat [])) +infExpr scope (ETyped e ty) = do + ty <- tcType scope ty + e <- tcExpr scope e (TTyp (scopeEnv scope) ty) + return (ETyped e ty,TTyp (scopeEnv scope) ty) +infExpr scope (EImplArg e) = do + (e,tty) <- infExpr scope e + return (EImplArg e,tty) +infExpr scope e = tcError (CannotInferType (scopeVars scope) e) + +tcArg scope e1 e2 delta ty0@(DTyp [] c es) = do + ty1 <- evalType (scopeSize scope) (TTyp delta ty0) + tcError (NotFunType (scopeVars scope) e1 ty1) +tcArg scope e1 (EImplArg e2) delta ty0@(DTyp ((Explicit,x,ty):hs) c es) = tcError (UnexpectedImplArg (scopeVars scope) e2) +tcArg scope e1 (EImplArg e2) delta ty0@(DTyp ((Implicit,x,ty):hs) c es) = do + e2 <- tcExpr scope e2 (TTyp delta ty) + funs <- getFuns + if x == wildCId + then return (EApp e1 (EImplArg e2), delta,DTyp hs c es) + else return (EApp e1 (EImplArg e2),eval funs (scopeEnv scope) e2:delta,DTyp hs c es) +tcArg scope e1 e2 delta ty0@(DTyp ((Explicit,x,ty):hs) c es) = do + e2 <- tcExpr scope e2 (TTyp delta ty) + funs <- getFuns + if x == wildCId + then return (EApp e1 e2, delta,DTyp hs c es) + else return (EApp e1 e2,eval funs (scopeEnv scope) e2:delta,DTyp hs c es) +tcArg scope e1 e2 delta ty0@(DTyp ((Implicit,x,ty):hs) c es) = do + i <- newMeta scope + if x == wildCId + then tcArg scope (EApp e1 (EImplArg (EMeta i))) e2 delta (DTyp hs c es) + else tcArg scope (EApp e1 (EImplArg (EMeta i))) e2 (VMeta i (scopeEnv scope) [] : delta) (DTyp hs c es) + +----------------------------------------------------- +-- eqType +----------------------------------------------------- + +eqType :: Scope -> Int -> MetaId -> TType -> TType -> TcM () +eqType scope k i0 tty1@(TTyp delta1 ty1@(DTyp hyps1 cat1 es1)) tty2@(TTyp delta2 ty2@(DTyp hyps2 cat2 es2)) + | cat1 == cat2 = do (k,delta1,delta2) <- eqHyps k delta1 hyps1 delta2 hyps2 + sequence_ [eqExpr k delta1 e1 delta2 e2 | (e1,e2) <- zip es1 es2] + | otherwise = raiseTypeMatchError + where + raiseTypeMatchError = do ty1 <- evalType k tty1 + ty2 <- evalType k tty2 + e <- refineExpr (EMeta i0) + tcError (TypeMismatch (scopeVars scope) e ty1 ty2) + + eqHyps :: Int -> Env -> [Hypo] -> Env -> [Hypo] -> TcM (Int,Env,Env) + eqHyps k delta1 [] delta2 [] = + return (k,delta1,delta2) + eqHyps k delta1 ((_,x,ty1) : h1s) delta2 ((_,y,ty2) : h2s) = do + eqType scope k i0 (TTyp delta1 ty1) (TTyp delta2 ty2) + if x == wildCId && y == wildCId + then eqHyps k delta1 h1s delta2 h2s + else if x /= wildCId && y /= wildCId + then eqHyps (k+1) ((VGen k []):delta1) h1s ((VGen k []):delta2) h2s + else raiseTypeMatchError + eqHyps k delta1 h1s delta2 h2s = raiseTypeMatchError + + eqExpr :: Int -> Env -> Expr -> Env -> Expr -> TcM () + eqExpr k env1 e1 env2 e2 = do + funs <- getFuns + eqValue k (eval funs env1 e1) (eval funs env2 e2) + + eqValue :: Int -> Value -> Value -> TcM () + eqValue k v1 v2 = do + v1 <- deRef v1 + v2 <- deRef v2 + eqValue' k v1 v2 + + deRef v@(VMeta i env vs) = do + mv <- getMeta i + funs <- getFuns + case mv of + MBound e -> deRef (apply funs env e vs) + MGuarded e _ x | x == 0 -> deRef (apply funs env e vs) + | otherwise -> return v + MUnbound _ _ -> return v + deRef v = return v + + eqValue' k (VSusp i env vs1 c) v2 = addConstraint i0 i env vs1 (\v1 -> eqValue k (c v1) v2) + eqValue' k v1 (VSusp i env vs2 c) = addConstraint i0 i env vs2 (\v2 -> eqValue k v1 (c v2)) + eqValue' k (VMeta i env1 vs1) (VMeta j env2 vs2) | i == j = zipWithM_ (eqValue k) vs1 vs2 + eqValue' k (VMeta i env1 vs1) v2 = do (MUnbound scopei cs) <- getMeta i + e2 <- mkLam i scopei env1 vs1 v2 + setMeta i (MBound e2) + sequence_ [c e2 | c <- cs] + eqValue' k v1 (VMeta i env2 vs2) = do (MUnbound scopei cs) <- getMeta i + e1 <- mkLam i scopei env2 vs2 v1 + setMeta i (MBound e1) + sequence_ [c e1 | c <- cs] + eqValue' k (VApp f1 vs1) (VApp f2 vs2) | f1 == f2 = zipWithM_ (eqValue k) vs1 vs2 + eqValue' k (VLit l1) (VLit l2 ) | l1 == l2 = return () + eqValue' k (VGen i vs1) (VGen j vs2) | i == j = zipWithM_ (eqValue k) vs1 vs2 + eqValue' k (VClosure env1 (EAbs _ x1 e1)) (VClosure env2 (EAbs _ x2 e2)) = let v = VGen k [] + in eqExpr (k+1) (v:env1) e1 (v:env2) e2 + eqValue' k v1 v2 = raiseTypeMatchError + + mkLam i scope env vs0 v = do + let k = scopeSize scope + vs = reverse (take k env) ++ vs0 + xs = nub [i | VGen i [] <- vs] + if length vs == length xs + then return () + else raiseTypeMatchError + v <- occurCheck i k xs v + funs <- getFuns + return (addLam vs0 (value2expr funs (length xs) v)) + where + addLam [] e = e + addLam (v:vs) e = EAbs Explicit var (addLam vs e) + + var = mkCId "v" + + occurCheck i0 k xs (VApp f vs) = do vs <- mapM (occurCheck i0 k xs) vs + return (VApp f vs) + occurCheck i0 k xs (VLit l) = return (VLit l) + occurCheck i0 k xs (VMeta i env vs) = do if i == i0 + then raiseTypeMatchError + else return () + mv <- getMeta i + funs <- getFuns + case mv of + MBound e -> occurCheck i0 k xs (apply funs env e vs) + MGuarded e _ _ -> occurCheck i0 k xs (apply funs env e vs) + MUnbound scopei _ | scopeSize scopei > k -> raiseTypeMatchError + | otherwise -> do vs <- mapM (occurCheck i0 k xs) vs + return (VMeta i env vs) + occurCheck i0 k xs (VSusp i env vs cnt) = do addConstraint i0 i env vs (\v -> occurCheck i0 k xs (cnt v) >> return ()) + return (VSusp i env vs cnt) + occurCheck i0 k xs (VGen i vs) = case List.findIndex (==i) xs of + Just i -> do vs <- mapM (occurCheck i0 k xs) vs + return (VGen i vs) + Nothing -> raiseTypeMatchError + occurCheck i0 k xs (VClosure env e) = do env <- mapM (occurCheck i0 k xs) env + return (VClosure env e) + + +----------------------------------------------------------- +-- check for meta variables that still have to be resolved +----------------------------------------------------------- + +checkResolvedMetaStore :: Scope -> Expr -> TcM () +checkResolvedMetaStore scope e = TcM (\abstr metaid ms -> + let xs = [i | (i,mv) <- IntMap.toList ms, not (isResolved mv)] + in if List.null xs + then Ok metaid ms () + else Fail (UnresolvedMetaVars (scopeVars scope) e xs)) + where + isResolved (MUnbound _ []) = True + isResolved (MGuarded _ _ _) = True + isResolved (MBound _) = True + isResolved _ = False + +----------------------------------------------------- +-- evalType +----------------------------------------------------- + +evalType :: Int -> TType -> TcM Type +evalType k (TTyp delta ty) = do funs <- getFuns + refineType (evalTy funs k delta ty) + where + evalTy sig k delta (DTyp hyps cat es) = + let ((k1,delta1),hyps1) = mapAccumL (evalHypo sig) (k,delta) hyps + in DTyp hyps1 cat (List.map (normalForm sig k1 delta1) es) + + evalHypo sig (k,delta) (b,x,ty) = + if x == wildCId + then ((k, delta),(b,x,evalTy sig k delta ty)) + else ((k+1,(VGen k []):delta),(b,x,evalTy sig k delta ty)) + + +----------------------------------------------------- +-- refinement +----------------------------------------------------- + +refineExpr :: Expr -> TcM Expr +refineExpr e = TcM (\abstr metaid ms -> Ok metaid ms (refineExpr_ ms e)) + +refineExpr_ ms e = refine e + where + refine (EAbs b x e) = EAbs b x (refine e) + refine (EApp e1 e2) = EApp (refine e1) (refine e2) + refine (ELit l) = ELit l + refine (EMeta i) = case IntMap.lookup i ms of + Just (MBound e ) -> refine e + Just (MGuarded e _ _) -> refine e + _ -> EMeta i + refine (EFun f) = EFun f + refine (EVar i) = EVar i + refine (ETyped e ty) = ETyped (refine e) (refineType_ ms ty) + refine (EImplArg e) = EImplArg (refine e) + +refineType :: Type -> TcM Type +refineType ty = TcM (\abstr metaid ms -> Ok metaid ms (refineType_ ms ty)) + +refineType_ ms (DTyp hyps cat es) = DTyp [(b,x,refineType_ ms ty) | (b,x,ty) <- hyps] cat (List.map (refineExpr_ ms) es) + +value2expr sig i (VApp f vs) = foldl EApp (EFun f) (List.map (value2expr sig i) vs) +value2expr sig i (VGen j vs) = foldl EApp (EVar (i-j-1)) (List.map (value2expr sig i) vs) +value2expr sig i (VMeta j env vs) = foldl EApp (EMeta j) (List.map (value2expr sig i) vs) +value2expr sig i (VSusp j env vs k) = value2expr sig i (k (VGen j vs)) +value2expr sig i (VLit l) = ELit l +value2expr sig i (VClosure env (EAbs b x e)) = EAbs b x (value2expr sig (i+1) (eval sig ((VGen i []):env) e)) diff --git a/src/runtime/haskell/PGF/VisualizeTree.hs b/src/runtime/haskell/PGF/VisualizeTree.hs new file mode 100644 index 000000000..429551f54 --- /dev/null +++ b/src/runtime/haskell/PGF/VisualizeTree.hs @@ -0,0 +1,353 @@ +---------------------------------------------------------------------- +-- | +-- Module : VisualizeTree +-- Maintainer : AR +-- Stability : (stable) +-- Portability : (portable) +-- +-- > CVS $Date: +-- > CVS $Author: +-- > CVS $Revision: +-- +-- Print a graph of an abstract syntax tree in Graphviz DOT format +-- Based on BB's VisualizeGrammar +-- FIXME: change this to use GF.Visualization.Graphviz, +-- instead of rolling its own. +----------------------------------------------------------------------------- + +module PGF.VisualizeTree ( graphvizAbstractTree + , graphvizParseTree + , graphvizDependencyTree + , graphvizAlignment + , tree2mk + , getDepLabels + , PosText(..), readPosText + ) where + +import PGF.CId (CId,showCId,pCId,mkCId) +import PGF.Data +import PGF.Tree +import PGF.Expr (showExpr) +import PGF.Linearize +import PGF.Macros (lookValCat) + +import qualified Data.Map as Map +import Data.List (intersperse,nub,isPrefixOf,sort,sortBy) +import Data.Char (isDigit) +import qualified Text.ParserCombinators.ReadP as RP + +import Debug.Trace + +graphvizAbstractTree :: PGF -> (Bool,Bool) -> Expr -> String +graphvizAbstractTree pgf funscats = prGraph False . tree2graph pgf funscats . expr2tree + +tree2graph :: PGF -> (Bool,Bool) -> Tree -> [String] +tree2graph pgf (funs,cats) = prf [] where + prf ps t = let (nod,lab) = prn ps t in + (nod ++ " [label = " ++ lab ++ ", style = \"solid\", shape = \"plaintext\"] ;") : + case t of + Fun cid trees -> + [ pra (j:ps) nod t | (j,t) <- zip [0..] trees] ++ + concat [prf (j:ps) t | (j,t) <- zip [0..] trees] + Abs xs (Fun cid trees) -> + [ pra (j:ps) nod t | (j,t) <- zip [0..] trees] ++ + concat [prf (j:ps) t | (j,t) <- zip [0..] trees] + _ -> [] + prn ps t = case t of + Fun cid _ -> + let + fun = if funs then showCId cid else "" + cat = if cats then prCat cid else "" + colon = if funs && cats then " : " else "" + lab = "\"" ++ fun ++ colon ++ cat ++ "\"" + in (show(show (ps :: [Int])),lab) + Abs bs tree -> + let fun = case tree of + Fun cid _ -> Fun cid [] + _ -> tree + in (show(show (ps :: [Int])),"\"" ++ esc (prTree (Abs bs fun)) ++ "\"") + _ -> (show(show (ps :: [Int])),"\"" ++ esc (prTree t) ++ "\"") + pra i nod t = nod ++ arr ++ fst (prn i t) ++ " [style = \"solid\"];" + arr = " -- " -- if digr then " -> " else " -- " + prCat = showCId . lookValCat pgf + esc = concatMap (\c -> if c =='\\' then [c,c] else [c]) --- escape backslash in abstracts + +prGraph digr ns = concat $ map (++"\n") $ [graph ++ "{\n"] ++ ns ++ ["}"] where + graph = if digr then "digraph" else "graph" + + +-- replace each non-atomic constructor with mkC, where C is the val cat +tree2mk :: PGF -> Expr -> String +tree2mk pgf = showExpr [] . tree2expr . t2m . expr2tree where + t2m t = case t of + Fun cid [] -> t + Fun cid ts -> Fun (mk cid) (map t2m ts) + _ -> t + mk = mkCId . ("mk" ++) . showCId . lookValCat pgf + +-- dependency trees from Linearize.linearizeMark + +graphvizDependencyTree :: String -> Bool -> Maybe Labels -> Maybe String -> PGF -> CId -> Expr -> String +graphvizDependencyTree format debug mlab ms pgf lang exp = case format of + "malt" -> unlines (lin2dep format) + "malt_input" -> unlines (lin2dep format) + _ -> prGraph True (lin2dep format) + + where + + lin2dep format = trace (ifd (show sortedNodes ++ show nodeWords)) $ case format of + "malt" -> map (concat . intersperse "\t") wnodes + "malt_input" -> map (concat . intersperse "\t" . take 6) wnodes + _ -> prelude ++ nodes ++ links + + ifd s = if debug then s else [] + + pot = readPosText $ head $ linearizesMark pgf lang exp + ---- use Just str if you have str to match against + + prelude = ["rankdir=LR ;", "node [shape = plaintext] ;"] + + nodes = map mkNode nodeWords + mkNode (i,((_,p),ss)) = + node p ++ " [label = \"" ++ show i ++ ". " ++ ifd (show p) ++ unwords ss ++ "\"] ;" + nodeWords = (0,((mkCId "",[]),["ROOT"])) : zip [1..] [((f,p),w)| + ((Just f,p),w) <- wlins pot] + + links = map mkLink thelinks + thelinks = [(word y, x, label tr y x) | + (_,((f,x),_)) <- tail nodeWords, + let y = dominant x] + mkLink (x,y,l) = node x ++ " -> " ++ node y ++ " [label = \"" ++ l ++ "\"] ;" + node = show . show + + dominant x = case x of + [] -> x + _ | not (x == hx) -> hx + _ -> dominant (init x) + where + hx = headArg (init x) tr x + + headArg x0 tr x = case (tr,x) of + (Fun f [],[_]) -> x0 ---- ?? + (Fun f ts,[_]) -> x0 ++ [getHead (length ts - 1) f] + (Fun f ts,i:y) -> headArg x0 (ts !! i) y + _ -> x0 ---- + + label tr y x = case span (uncurry (==)) (zip y x) of + (xys,(_,i):_) -> getLabel i (funAt tr (map fst xys)) + _ -> "" ---- + + funAt tr x = case (tr,x) of + (Fun f _ ,[]) -> f + (Fun f ts,i:y) -> funAt (ts !! i) y + _ -> mkCId (prTree tr) ---- + + word x = if elem x sortedNodes then x else + let x' = headArg x tr (x ++[0]) in + if x' == x then [] else word x' + + tr = expr2tree exp + sortedNodes = [p | (_,((_,p),_)) <- nodeWords] + + labels = maybe Map.empty id mlab + getHead i f = case Map.lookup f labels of + Just ls -> length $ takeWhile (/= "head") ls + _ -> i + getLabel i f = case Map.lookup f labels of + Just ls | length ls > i -> ifd (showCId f ++ "#" ++ show i ++ "=") ++ ls !! i + _ -> showCId f ++ "#" ++ show i + +-- to generate CoNLL format for MaltParser + nodeMap :: Map.Map [Int] Int + nodeMap = Map.fromList [(p,i) | (i,((_,p),_)) <- nodeWords] + + arcMap :: Map.Map [Int] ([Int],String) + arcMap = Map.fromList [(y,(x,l)) | (x,y,l) <- thelinks] + + lookDomLab p = case Map.lookup p arcMap of + Just (q,l) -> (maybe 0 id (Map.lookup q nodeMap), if null l then rootlabel else l) + _ -> (0,rootlabel) + + wnodes = [[show i, maltws ws, showCId fun, pos, pos, morph, show dom, lab, unspec, unspec] | + (i, ((fun,p),ws)) <- tail nodeWords, + let pos = showCId $ lookValCat pgf fun, + let morph = unspec, + let (dom,lab) = lookDomLab p + ] + maltws = concat . intersperse "+" . words . unwords -- no spaces in column 2 + unspec = "_" + rootlabel = "ROOT" + +type Labels = Map.Map CId [String] + +getDepLabels :: [String] -> Labels +getDepLabels ss = Map.fromList [(mkCId f,ls) | f:ls <- map words ss] + + +-- parse trees from Linearize.linearizeMark +---- nubrec and domins are quadratic, but could be (n log n) + +graphvizParseTree :: PGF -> CId -> Expr -> String +graphvizParseTree pgf lang = prGraph False . lin2tree pgf . linMark where + linMark = head . linearizesMark pgf lang + ---- use Just str if you have str to match against + +lin2tree pgf s = trace s $ prelude ++ nodes ++ links where + + prelude = ["rankdir=BU ;", "node [shape = record, color = white] ;"] + + nodeRecs = zip [0..] + (nub (filter (not . null) (nlins [postext] ++ [leaves postext]))) + nlins pts = + nubrec [] $ [(p,cat f) | T (Just f, p) _ <- pts] : + concatMap nlins [ts | T _ ts <- pts] + leaves pt = [(p++[j],s) | (j,(p,s)) <- + zip [9990..] [(p,s) | ((_,p),ss) <- wlins pt, s <- ss]] + + nubrec es rs = case rs of + r:rr -> let r' = filter (not . flip elem es) (nub r) + in r' : nubrec (r' ++ es) rr + _ -> rs + + nodes = map mkStruct nodeRecs + + mkStruct (i,cs) = struct i ++ "[label = \"" ++ fields cs ++ "\"] ;" + cat = showCId . lookValCat pgf + fields cs = concat (intersperse "|" [ mtag (showp p) ++ c | (p,c) <- cs]) + struct i = "struct" ++ show i + + links = map mkEdge domins + domins = nub [((i,x),(j,y)) | + (i,xs) <- nodeRecs, (j,ys) <- nodeRecs, + x <- xs, y <- ys, dominates x y] + dominates (p,x) (q,y) = not (null q) && p == init q + mkEdge ((i,x),(j,y)) = + struct i ++ ":n" ++ uncommas (showp (fst x)) ++ ":s -- " ++ + struct j ++ ":n" ++ uncommas (showp (fst y)) ++ ":n ;" + + postext = readPosText s + +-- auxiliaries for graphviz syntax +struct i = "struct" ++ show i +mark (j,n) = "n" ++ show j ++ "a" ++ uncommas n +uncommas = map (\c -> if c==',' then 'c' else c) +tag s = "<" ++ s ++ ">" +showp = init . tail . show +mtag = tag . ('n':) . uncommas + +-- word alignments from Linearize.linearizesMark +-- words are chunks like {[0,1,1,0] old} + +graphvizAlignment :: PGF -> Expr -> String +graphvizAlignment pgf = prGraph True . lin2graph . linsMark where + linsMark t = [s | la <- cncnames pgf, s <- take 1 (linearizesMark pgf la t)] + +lin2graph :: [String] -> [String] +lin2graph ss = trace (show ss) $ prelude ++ nodes ++ links + + where + + prelude = ["rankdir=LR ;", "node [shape = record] ;"] + + nlins :: [(Int,[((Int,String),String)])] + nlins = [(i, [((j,showp p),unw ws) | (j,((_,p),ws)) <- zip [0..] ws]) | + (i,ws) <- zip [0..] (map (wlins . readPosText) ss)] + + unw = concat . intersperse "\\ " -- space escape in graphviz + + nodes = map mkStruct nlins + + mkStruct (i, ws) = struct i ++ "[label = \"" ++ fields ws ++ "\"] ;" + + fields ws = concat (intersperse "|" [tag (mark m) ++ " " ++ w | (m,w) <- ws]) + + links = nub $ concatMap mkEdge (init nlins) + + mkEdge (i,lin) = let lin' = snd (nlins !! (i+1)) in -- next lin in the list + [edge i v w | (v@(_,p),_) <- lin, (w@(_,q),_) <- lin', p == q] + + edge i v w = + struct i ++ ":" ++ mark v ++ ":e -> " ++ struct (i+1) ++ ":" ++ mark w ++ ":w ;" +{- +alignmentData :: PGF -> [Expr] -> Map.Map String (Map.Map String Double) +alignmentData pgf = mkStat . concatMap (mkAlign . linsMark) where + linsMark t = + [s | la <- take 2 (cncnames pgf), s <- take 1 (linearizesMark pgf la t)] + + mkStat :: [(String,String)] -> Map.Map String (Map.Map String Double) + mkStat = + + mkAlign :: [String] -> [(String,String)] + mkAlign ss = + + nlins :: [(Int,[((Int,String),String)])] + nlins = [(i, [((j,showp p),unw ws) | (j,((_,p),ws)) <- zip [0..] vs]) | + (i,vs) <- zip [0..] (map (wlins . readPosText) ss)] + + nodes = map mkStruct nlins + + mkStruct (i, ws) = struct i ++ "[label = \"" ++ fields ws ++ "\"] ;" + + fields ws = concat (intersperse "|" [tag (mark m) ++ " " ++ w | (m,w) <- ws]) + + links = nub $ concatMap mkEdge (init nlins) + + mkEdge (i,lin) = let lin' = snd (nlins !! (i+1)) in -- next lin in the list + [edge i v w | (v@(_,p),_) <- lin, (w@(_,q),_) <- lin', p == q] + + edge i v w = + struct i ++ ":" ++ mark v ++ ":e -> " ++ struct (i+1) ++ ":" ++ mark w ++ ":w ;" +-} + +wlins :: PosText -> [((Maybe CId,[Int]),[String])] +wlins pt = case pt of + T p pts -> concatMap (lins p) pts + M ws -> if null ws then [] else [((Nothing,[]),ws)] + where + lins p pt = case pt of + T q pts -> concatMap (lins q) pts + M ws -> if null ws then [] else [(p,ws)] + +data PosText = + T (Maybe CId,[Int]) [PosText] + | M [String] + deriving Show + +readPosText :: String -> PosText +readPosText = fst . head . (RP.readP_to_S pPosText) where + pPosText = do + RP.char '(' >> RP.skipSpaces + p <- pPos + RP.skipSpaces + ts <- RP.many pPosText + RP.char ')' >> RP.skipSpaces + return (T p ts) + RP.<++ do + ws <- RP.sepBy1 (RP.munch1 (flip notElem "()")) (RP.char ' ') + return (M ws) + pPos = do + fun <- (RP.char '(' >> pCId >>= \f -> RP.char ',' >> (return $ Just f)) + RP.<++ (return Nothing) + RP.char '[' >> RP.skipSpaces + is <- RP.sepBy (RP.munch1 isDigit) (RP.char ',') + RP.char ']' >> RP.skipSpaces + RP.char ')' RP.<++ return ' ' + return (fun,map read is) + + +{- +digraph{ +rankdir ="LR" ; +node [shape = record] ; + +struct1 [label = "<f0> this|<f1> very|<f2> intelligent|<f3> man"] ; +struct2 [label = "<f0> cet|<f1> homme|<f2> tres|<f3> intelligent|<f4> ci"] ; + +struct1:f0 -> struct2:f0 ; +struct1:f1 -> struct2:f2 ; +struct1:f2 -> struct2:f3 ; +struct1:f3 -> struct2:f1 ; +struct1:f0 -> struct2:f4 ; +} +-} + diff --git a/src/runtime/javascript/editor.html b/src/runtime/javascript/editor.html new file mode 100644 index 000000000..dd189d9ab --- /dev/null +++ b/src/runtime/javascript/editor.html @@ -0,0 +1,17 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <link rel="stylesheet" type="text/css" href="style.css" />
+ <script type="text/javascript" src="gflib.js"></script>
+ <script type="text/javascript" src="editorGrammar.js"></script>
+ <script type="text/javascript" src="grammar.js"></script>
+ <script type="text/javascript" src="gfjseditor.js"></script>
+ <title>Web-based Syntax Editor</title>
+ </head>
+ <body onload="mkEditor('editor', Food)" onkeydown="hotKeys(event)">
+ <div id="editor">
+ </div>
+ </body>
+</html>
diff --git a/src/runtime/javascript/editorGrammar.js b/src/runtime/javascript/editorGrammar.js new file mode 100644 index 000000000..a4cc01ea5 --- /dev/null +++ b/src/runtime/javascript/editorGrammar.js @@ -0,0 +1 @@ +var Editor = new GFGrammar(new GFAbstract("Sentence",{Available: new Type([], "Adjective"), Bulgarian: new Type([], "Noun"), Command: new Type(["Verb", "Determiner", "Noun"], "Sentence"), CommandAdj: new Type(["Verb", "Determiner", "Adjective", "Noun"], "Sentence"), Copy: new Type([], "Verb"), Cut: new Type([], "Verb"), Danish: new Type([], "Noun"), DefPlDet: new Type([], "Determiner"), DefSgDet: new Type([], "Determiner"), Delete: new Type([], "Verb"), English: new Type([], "Noun"), Enter: new Type([], "Verb"), ErrorMessage: new Type(["Adjective", "Noun"], "Sentence"), Finnish: new Type([], "Noun"), Float_N: new Type([], "Noun"), French: new Type([], "Noun"), German: new Type([], "Noun"), IndefPlDet: new Type([], "Determiner"), IndefSgDet: new Type([], "Determiner"), Integer_N: new Type([], "Noun"), Italian: new Type([], "Noun"), Label: new Type(["Noun"], "Sentence"), Language: new Type([], "Noun"), Next: new Type([], "Adjective"), Node: new Type([], "Noun"), Norwegian: new Type([], "Noun"), Page: new Type([], "Noun"), Parse: new Type([], "Verb"), Paste: new Type([], "Verb"), Previous: new Type([], "Adjective"), RandomlyCommand: new Type(["Verb", "Determiner", "Noun"], "Sentence"), Redo: new Type([], "Verb"), Refine: new Type([], "Verb"), Refinement: new Type([], "Noun"), Replace: new Type([], "Verb"), Russian: new Type([], "Noun"), Select: new Type([], "Verb"), Show: new Type([], "Verb"), SingleWordCommand: new Type(["Verb"], "Sentence"), Spanish: new Type([], "Noun"), String_N: new Type([], "Noun"), Swedish: new Type([], "Noun"), Tree: new Type([], "Noun"), Undo: new Type([], "Verb"), Wrap: new Type([], "Verb"), Wrapper: new Type([], "Noun")}),{EditorEng: new GFConcrete({coding: "utf8"},{Available: function(cs){return new Arr(new Suffix("available", new Arr(new Str(""), new Str("r"), new Str("st"), new Str("ly"))));}, Bulgarian: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_4", cs), Editor.concretes["EditorEng"].rule("_4", cs)), new Int(0));}, Command: function(cs){return new Arr(new Seq(Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_11", cs), Editor.concretes["EditorEng"].rule("_14", cs), Editor.concretes["EditorEng"].rule("_18", cs)));}, CommandAdj: function(cs){return new Arr(new Seq(Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_11", cs),(new Arr(Editor.concretes["EditorEng"].rule("_13", cs), Editor.concretes["EditorEng"].rule("_13", cs), Editor.concretes["EditorEng"].rule("_13", cs), Editor.concretes["EditorEng"].rule("_13", cs), Editor.concretes["EditorEng"].rule("_13", cs), Editor.concretes["EditorEng"].rule("_13", cs), Editor.concretes["EditorEng"].rule("_13", cs), Editor.concretes["EditorEng"].rule("_13", cs))).sel(Editor.concretes["EditorEng"].rule("_22", cs).sel(cs[3].sel(new Int(1)))), cs[3].sel(new Int(0)).sel(new Int(0)).sel(new Int(1)), Editor.concretes["EditorEng"].rule("_18", cs)));}, Copy: function(cs){return new Arr(new Suffix("Cop", new Arr(new Str("y"), new Str("ies"), new Str("ied"), new Str("ying"))), new Int(1));}, Cut: function(cs){return new Arr(new Suffix("Cut", Editor.concretes["EditorEng"].rule("_34", cs)), new Int(1));}, Danish: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_37", cs), Editor.concretes["EditorEng"].rule("_37", cs)), new Int(0));}, DefPlDet: function(cs){return Editor.concretes["EditorEng"].rule("_43", cs);}, DefSgDet: function(cs){return Editor.concretes["EditorEng"].rule("_43", cs);}, Delete: function(cs){return new Arr(new Suffix("Delet", Editor.concretes["EditorEng"].rule("_44", cs)), new Int(1));}, English: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_47", cs), Editor.concretes["EditorEng"].rule("_47", cs)), new Int(0));}, Enter: function(cs){return new Arr(new Suffix("Enter", Editor.concretes["EditorEng"].rule("_34", cs)), new Int(1));}, ErrorMessage: function(cs){return new Arr(new Seq(new Str("there"),(new Arr(new Seq(new Str("am"), new Str("not")), new Str("aren't"), new Str("aren't"), new Str("aren't"), new Str("isn't"), new Str("isn't"), new Str("isn't"), new Str("aren't"))).sel(Editor.concretes["EditorEng"].rule("_59", cs)), Editor.concretes["EditorEng"].rule("_62", cs), Editor.concretes["EditorEng"].rule("_62", cs), Editor.concretes["EditorEng"].rule("_62", cs),(new Arr(Editor.concretes["EditorEng"].rule("_67", cs), Editor.concretes["EditorEng"].rule("_67", cs), Editor.concretes["EditorEng"].rule("_67", cs), Editor.concretes["EditorEng"].rule("_67", cs), Editor.concretes["EditorEng"].rule("_67", cs), Editor.concretes["EditorEng"].rule("_67", cs), Editor.concretes["EditorEng"].rule("_67", cs), Editor.concretes["EditorEng"].rule("_67", cs))).sel(Editor.concretes["EditorEng"].rule("_59", cs))));}, Finnish: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_72", cs), Editor.concretes["EditorEng"].rule("_72", cs)), new Int(0));}, Float_N: function(cs){return new Arr(new Arr(new Suffix("float", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("floats", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, French: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_80", cs), Editor.concretes["EditorEng"].rule("_80", cs)), new Int(0));}, German: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_83", cs), Editor.concretes["EditorEng"].rule("_83", cs)), new Int(0));}, IndefPlDet: function(cs){return Editor.concretes["EditorEng"].rule("_89", cs);}, IndefSgDet: function(cs){return Editor.concretes["EditorEng"].rule("_89", cs);}, Integer_N: function(cs){return new Arr(new Arr(new Suffix("integer", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("integers", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, Italian: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_94", cs), Editor.concretes["EditorEng"].rule("_94", cs)), new Int(0));}, Label: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_8", cs).sel(new Int(0)));}, Language: function(cs){return new Arr(new Arr(new Suffix("language", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("languages", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, Next: function(cs){return new Arr(new Suffix("next", Editor.concretes["EditorEng"].rule("_103", cs)));}, Node: function(cs){return new Arr(new Arr(new Suffix("node", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("nodes", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, Norwegian: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_110", cs), Editor.concretes["EditorEng"].rule("_110", cs)), new Int(0));}, Page: function(cs){return new Arr(new Arr(new Suffix("page", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("pages", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, Parse: function(cs){return new Arr(new Suffix("Pars", Editor.concretes["EditorEng"].rule("_44", cs)), new Int(1));}, Paste: function(cs){return new Arr(new Suffix("Past", Editor.concretes["EditorEng"].rule("_44", cs)), new Int(1));}, Previous: function(cs){return new Arr(new Suffix("previous", Editor.concretes["EditorEng"].rule("_103", cs)));}, RandomlyCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_11", cs), Editor.concretes["EditorEng"].rule("_14", cs), Editor.concretes["EditorEng"].rule("_18", cs), new Str("at"), new Str("random")));}, Redo: function(cs){return new Arr(new Suffix("Redo", Editor.concretes["EditorEng"].rule("_125", cs)), new Int(1));}, Refine: function(cs){return new Arr(new Suffix("Refin", Editor.concretes["EditorEng"].rule("_44", cs)), new Int(1));}, Refinement: function(cs){return new Arr(new Arr(new Suffix("refinement", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("refinements", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, Replace: function(cs){return new Arr(new Suffix("Replac", Editor.concretes["EditorEng"].rule("_44", cs)), new Int(1));}, Russian: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_136", cs), Editor.concretes["EditorEng"].rule("_136", cs)), new Int(0));}, Select: function(cs){return new Arr(new Suffix("Select", Editor.concretes["EditorEng"].rule("_34", cs)), new Int(1));}, Show: function(cs){return new Arr(new Suffix("Show", Editor.concretes["EditorEng"].rule("_34", cs)), new Int(1));}, SingleWordCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_18", cs)));}, Spanish: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_145", cs), Editor.concretes["EditorEng"].rule("_145", cs)), new Int(0));}, String_N: function(cs){return new Arr(new Arr(new Suffix("string", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("strings", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, Swedish: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_152", cs), Editor.concretes["EditorEng"].rule("_152", cs)), new Int(0));}, Tree: function(cs){return new Arr(new Arr(new Suffix("tree", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("trees", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, Undo: function(cs){return new Arr(new Suffix("Undo", Editor.concretes["EditorEng"].rule("_125", cs)), new Int(1));}, Wrap: function(cs){return new Arr(new Suffix("Wrap", Editor.concretes["EditorEng"].rule("_34", cs)), new Int(1));}, Wrapper: function(cs){return new Arr(new Arr(new Suffix("wrapper", Editor.concretes["EditorEng"].rule("_3", cs)), new Suffix("wrappers", Editor.concretes["EditorEng"].rule("_76", cs))), new Int(0));}, _10: function(cs){return Editor.concretes["EditorEng"].rule("_9", cs).sel(new Int(1));}, _103: function(cs){return new Arr(new Str(""), new Str("er"), new Str("est"), new Str("ly"));}, _11: function(cs){return Editor.concretes["EditorEng"].rule("_10", cs).sel(new Int(0));}, _110: function(cs){return new Suffix("Norwegian", Editor.concretes["EditorEng"].rule("_3", cs));}, _12: function(cs){return cs[2].sel(new Int(0));}, _125: function(cs){return new Arr(new Str(""), new Str("es"), new Str("ed"), new Str("ing"));}, _13: function(cs){return Editor.concretes["EditorEng"].rule("_12", cs).sel(new Int(0));}, _136: function(cs){return new Suffix("Russian", Editor.concretes["EditorEng"].rule("_3", cs));}, _14: function(cs){return Editor.concretes["EditorEng"].rule("_13", cs).sel(new Int(1));}, _145: function(cs){return new Suffix("Spanish", Editor.concretes["EditorEng"].rule("_3", cs));}, _15: function(cs){return new Seq();}, _152: function(cs){return new Suffix("Swedish", Editor.concretes["EditorEng"].rule("_3", cs));}, _16: function(cs){return new Arr(new Str("yourself"), Editor.concretes["EditorEng"].rule("_15", cs));}, _167: function(cs){return new Arr(cs[0], cs[0], cs[0], cs[0]);}, _169: function(cs){return new Arr(cs[0], cs[0]);}, _17: function(cs){return cs[0].sel(new Int(1));}, _172: function(cs){return new Arr(cs[0], cs[0], cs[0]);}, _18: function(cs){return Editor.concretes["EditorEng"].rule("_16", cs).sel(Editor.concretes["EditorEng"].rule("_17", cs));}, _22: function(cs){return new Arr(new Int(4), new Int(5), new Int(6));}, _3: function(cs){return new Arr(new Str(""), new Str(""), new Str("'s"));}, _34: function(cs){return new Arr(new Str(""), new Str("s"), new Str("ed"), new Str("ing"));}, _37: function(cs){return new Suffix("Danish", Editor.concretes["EditorEng"].rule("_3", cs));}, _4: function(cs){return new Suffix("Bulgarian", Editor.concretes["EditorEng"].rule("_3", cs));}, _40: function(cs){return new Arr(new Str(""), new Str(""));}, _41: function(cs){return new Suffix("the", Editor.concretes["EditorEng"].rule("_40", cs));}, _42: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_41", cs), Editor.concretes["EditorEng"].rule("_41", cs));}, _43: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_42", cs));}, _44: function(cs){return new Arr(new Str("e"), new Str("es"), new Str("ed"), new Str("ing"));}, _47: function(cs){return new Suffix("English", Editor.concretes["EditorEng"].rule("_3", cs));}, _54: function(cs){return new Arr(new Int(4), new Int(7));}, _55: function(cs){return new Arr(new Int(0), new Int(1), new Int(0), new Int(1), new Int(0), new Int(0), new Int(0), new Int(1));}, _56: function(cs){return cs[1].sel(new Int(1));}, _57: function(cs){return Editor.concretes["EditorEng"].rule("_22", cs).sel(Editor.concretes["EditorEng"].rule("_56", cs));}, _58: function(cs){return Editor.concretes["EditorEng"].rule("_55", cs).sel(Editor.concretes["EditorEng"].rule("_57", cs));}, _59: function(cs){return Editor.concretes["EditorEng"].rule("_54", cs).sel(Editor.concretes["EditorEng"].rule("_58", cs));}, _61: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs));}, _62: function(cs){return Editor.concretes["EditorEng"].rule("_61", cs).sel(Editor.concretes["EditorEng"].rule("_59", cs));}, _63: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_8", cs), Editor.concretes["EditorEng"].rule("_8", cs));}, _64: function(cs){return Editor.concretes["EditorEng"].rule("_63", cs).sel(Editor.concretes["EditorEng"].rule("_57", cs));}, _65: function(cs){return Editor.concretes["EditorEng"].rule("_9", cs).sel(new Int(0));}, _66: function(cs){return Editor.concretes["EditorEng"].rule("_65", cs).sel(new Int(1));}, _67: function(cs){return new Seq(new Str("a"), Editor.concretes["EditorEng"].rule("_64", cs), Editor.concretes["EditorEng"].rule("_66", cs));}, _7: function(cs){return cs[0].sel(new Int(0));}, _72: function(cs){return new Suffix("Finnish", Editor.concretes["EditorEng"].rule("_3", cs));}, _76: function(cs){return new Arr(new Str(""), new Str(""), new Str("'"));}, _8: function(cs){return Editor.concretes["EditorEng"].rule("_7", cs).sel(new Int(0));}, _80: function(cs){return new Suffix("French", Editor.concretes["EditorEng"].rule("_3", cs));}, _83: function(cs){return new Suffix("German", Editor.concretes["EditorEng"].rule("_3", cs));}, _86: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_15", cs), Editor.concretes["EditorEng"].rule("_15", cs));}, _87: function(cs){return new Arr(new Str("a"), Editor.concretes["EditorEng"].rule("_15", cs));}, _88: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_86", cs), Editor.concretes["EditorEng"].rule("_87", cs));}, _89: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_88", cs));}, _9: function(cs){return cs[1].sel(new Int(0));}, _94: function(cs){return new Suffix("Italian", Editor.concretes["EditorEng"].rule("_3", cs));}, Adjective: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_167", cs));}, Determiner: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_169", cs), Editor.concretes["EditorEng"].rule("_169", cs)));}, Noun: function(cs){return new Arr(new Arr(Editor.concretes["EditorEng"].rule("_172", cs), Editor.concretes["EditorEng"].rule("_172", cs)), new Int(0));}, Sentence: function(cs){return new Arr(cs[0]);}, Verb: function(cs){return new Arr(Editor.concretes["EditorEng"].rule("_167", cs), new Int(0));}, "Int": function(cs){return new Arr(cs[0]);}, "Float": function(cs){return new Arr(cs[0]);}, "String": function(cs){return new Arr(cs[0]);}}, new Parser("Sentence",[new Rule(10, new FunApp("Wrapper",[]),[],[[new Terminal("wrapper")]]), new Rule(9, new FunApp("Wrapper",[]),[],[[new Terminal("wrapper")]]), new Rule(8, new FunApp("Wrapper",[]),[],[[new Terminal("wrapper's")]]), new Rule(7, new FunApp("Wrapper",[]),[],[[new Terminal("wrappers")]]), new Rule(6, new FunApp("Wrapper",[]),[],[[new Terminal("wrappers")]]), new Rule(5, new FunApp("Wrapper",[]),[],[[new Terminal("wrappers'")]]), new Rule(17, new FunApp("Wrap",[]),[],[[new Terminal("Wrap")]]), new Rule(20, new FunApp("Wrap",[]),[],[[new Terminal("Wraps")]]), new Rule(19, new FunApp("Wrap",[]),[],[[new Terminal("Wraped")]]), new Rule(18, new FunApp("Wrap",[]),[],[[new Terminal("Wraping")]]), new Rule(17, new FunApp("Undo",[]),[],[[new Terminal("Undo")]]), new Rule(20, new FunApp("Undo",[]),[],[[new Terminal("Undoes")]]), new Rule(19, new FunApp("Undo",[]),[],[[new Terminal("Undoed")]]), new Rule(18, new FunApp("Undo",[]),[],[[new Terminal("Undoing")]]), new Rule(10, new FunApp("Tree",[]),[],[[new Terminal("tree")]]), new Rule(9, new FunApp("Tree",[]),[],[[new Terminal("tree")]]), new Rule(8, new FunApp("Tree",[]),[],[[new Terminal("tree's")]]), new Rule(7, new FunApp("Tree",[]),[],[[new Terminal("trees")]]), new Rule(6, new FunApp("Tree",[]),[],[[new Terminal("trees")]]), new Rule(5, new FunApp("Tree",[]),[],[[new Terminal("trees'")]]), new Rule(10, new FunApp("Swedish",[]),[],[[new Terminal("Swedish")]]), new Rule(9, new FunApp("Swedish",[]),[],[[new Terminal("Swedish")]]), new Rule(8, new FunApp("Swedish",[]),[],[[new Terminal("Swedish's")]]), new Rule(7, new FunApp("Swedish",[]),[],[[new Terminal("Swedish")]]), new Rule(6, new FunApp("Swedish",[]),[],[[new Terminal("Swedish")]]), new Rule(5, new FunApp("Swedish",[]),[],[[new Terminal("Swedish's")]]), new Rule(10, new FunApp("String_N",[]),[],[[new Terminal("string")]]), new Rule(9, new FunApp("String_N",[]),[],[[new Terminal("string")]]), new Rule(8, new FunApp("String_N",[]),[],[[new Terminal("string's")]]), new Rule(7, new FunApp("String_N",[]),[],[[new Terminal("strings")]]), new Rule(6, new FunApp("String_N",[]),[],[[new Terminal("strings")]]), new Rule(5, new FunApp("String_N",[]),[],[[new Terminal("strings'")]]), new Rule(10, new FunApp("Spanish",[]),[],[[new Terminal("Spanish")]]), new Rule(9, new FunApp("Spanish",[]),[],[[new Terminal("Spanish")]]), new Rule(8, new FunApp("Spanish",[]),[],[[new Terminal("Spanish's")]]), new Rule(7, new FunApp("Spanish",[]),[],[[new Terminal("Spanish")]]), new Rule(6, new FunApp("Spanish",[]),[],[[new Terminal("Spanish")]]), new Rule(5, new FunApp("Spanish",[]),[],[[new Terminal("Spanish's")]]), new Rule(11, new FunApp("SingleWordCommand",[new Arg(0)]),[17],[[new ArgProj(0, 0)]]), new Rule(11, new FunApp("SingleWordCommand",[new Arg(0)]),[16],[[new ArgProj(0, 0), new Terminal("yourself")]]), new Rule(17, new FunApp("Show",[]),[],[[new Terminal("Show")]]), new Rule(20, new FunApp("Show",[]),[],[[new Terminal("Shows")]]), new Rule(19, new FunApp("Show",[]),[],[[new Terminal("Showed")]]), new Rule(18, new FunApp("Show",[]),[],[[new Terminal("Showing")]]), new Rule(17, new FunApp("Select",[]),[],[[new Terminal("Select")]]), new Rule(20, new FunApp("Select",[]),[],[[new Terminal("Selects")]]), new Rule(19, new FunApp("Select",[]),[],[[new Terminal("Selected")]]), new Rule(18, new FunApp("Select",[]),[],[[new Terminal("Selecting")]]), new Rule(10, new FunApp("Russian",[]),[],[[new Terminal("Russian")]]), new Rule(9, new FunApp("Russian",[]),[],[[new Terminal("Russian")]]), new Rule(8, new FunApp("Russian",[]),[],[[new Terminal("Russian's")]]), new Rule(7, new FunApp("Russian",[]),[],[[new Terminal("Russian")]]), new Rule(6, new FunApp("Russian",[]),[],[[new Terminal("Russian")]]), new Rule(5, new FunApp("Russian",[]),[],[[new Terminal("Russian's")]]), new Rule(17, new FunApp("Replace",[]),[],[[new Terminal("Replace")]]), new Rule(20, new FunApp("Replace",[]),[],[[new Terminal("Replaces")]]), new Rule(19, new FunApp("Replace",[]),[],[[new Terminal("Replaced")]]), new Rule(18, new FunApp("Replace",[]),[],[[new Terminal("Replacing")]]), new Rule(10, new FunApp("Refinement",[]),[],[[new Terminal("refinement")]]), new Rule(9, new FunApp("Refinement",[]),[],[[new Terminal("refinement")]]), new Rule(8, new FunApp("Refinement",[]),[],[[new Terminal("refinement's")]]), new Rule(7, new FunApp("Refinement",[]),[],[[new Terminal("refinements")]]), new Rule(6, new FunApp("Refinement",[]),[],[[new Terminal("refinements")]]), new Rule(5, new FunApp("Refinement",[]),[],[[new Terminal("refinements'")]]), new Rule(17, new FunApp("Refine",[]),[],[[new Terminal("Refine")]]), new Rule(20, new FunApp("Refine",[]),[],[[new Terminal("Refines")]]), new Rule(19, new FunApp("Refine",[]),[],[[new Terminal("Refined")]]), new Rule(18, new FunApp("Refine",[]),[],[[new Terminal("Refining")]]), new Rule(17, new FunApp("Redo",[]),[],[[new Terminal("Redo")]]), new Rule(20, new FunApp("Redo",[]),[],[[new Terminal("Redoes")]]), new Rule(19, new FunApp("Redo",[]),[],[[new Terminal("Redoed")]]), new Rule(18, new FunApp("Redo",[]),[],[[new Terminal("Redoing")]]), new Rule(11, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[17, 15, 12],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("at"), new Terminal("random")]]), new Rule(11, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[16, 15, 12],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("yourself"), new Terminal("at"), new Terminal("random")]]), new Rule(4, new FunApp("Previous",[]),[],[[new Terminal("previous")]]), new Rule(3, new FunApp("Previous",[]),[],[[new Terminal("previouser")]]), new Rule(2, new FunApp("Previous",[]),[],[[new Terminal("previousest")]]), new Rule(1, new FunApp("Previous",[]),[],[[new Terminal("previously")]]), new Rule(17, new FunApp("Paste",[]),[],[[new Terminal("Paste")]]), new Rule(20, new FunApp("Paste",[]),[],[[new Terminal("Pastes")]]), new Rule(19, new FunApp("Paste",[]),[],[[new Terminal("Pasted")]]), new Rule(18, new FunApp("Paste",[]),[],[[new Terminal("Pasting")]]), new Rule(17, new FunApp("Parse",[]),[],[[new Terminal("Parse")]]), new Rule(20, new FunApp("Parse",[]),[],[[new Terminal("Parses")]]), new Rule(19, new FunApp("Parse",[]),[],[[new Terminal("Parsed")]]), new Rule(18, new FunApp("Parse",[]),[],[[new Terminal("Parsing")]]), new Rule(10, new FunApp("Page",[]),[],[[new Terminal("page")]]), new Rule(9, new FunApp("Page",[]),[],[[new Terminal("page")]]), new Rule(8, new FunApp("Page",[]),[],[[new Terminal("page's")]]), new Rule(7, new FunApp("Page",[]),[],[[new Terminal("pages")]]), new Rule(6, new FunApp("Page",[]),[],[[new Terminal("pages")]]), new Rule(5, new FunApp("Page",[]),[],[[new Terminal("pages'")]]), new Rule(10, new FunApp("Norwegian",[]),[],[[new Terminal("Norwegian")]]), new Rule(9, new FunApp("Norwegian",[]),[],[[new Terminal("Norwegian")]]), new Rule(8, new FunApp("Norwegian",[]),[],[[new Terminal("Norwegian's")]]), new Rule(7, new FunApp("Norwegian",[]),[],[[new Terminal("Norwegian")]]), new Rule(6, new FunApp("Norwegian",[]),[],[[new Terminal("Norwegian")]]), new Rule(5, new FunApp("Norwegian",[]),[],[[new Terminal("Norwegian's")]]), new Rule(10, new FunApp("Node",[]),[],[[new Terminal("node")]]), new Rule(9, new FunApp("Node",[]),[],[[new Terminal("node")]]), new Rule(8, new FunApp("Node",[]),[],[[new Terminal("node's")]]), new Rule(7, new FunApp("Node",[]),[],[[new Terminal("nodes")]]), new Rule(6, new FunApp("Node",[]),[],[[new Terminal("nodes")]]), new Rule(5, new FunApp("Node",[]),[],[[new Terminal("nodes'")]]), new Rule(4, new FunApp("Next",[]),[],[[new Terminal("next")]]), new Rule(3, new FunApp("Next",[]),[],[[new Terminal("nexter")]]), new Rule(2, new FunApp("Next",[]),[],[[new Terminal("nextest")]]), new Rule(1, new FunApp("Next",[]),[],[[new Terminal("nextly")]]), new Rule(10, new FunApp("Language",[]),[],[[new Terminal("language")]]), new Rule(9, new FunApp("Language",[]),[],[[new Terminal("language")]]), new Rule(8, new FunApp("Language",[]),[],[[new Terminal("language's")]]), new Rule(7, new FunApp("Language",[]),[],[[new Terminal("languages")]]), new Rule(6, new FunApp("Language",[]),[],[[new Terminal("languages")]]), new Rule(5, new FunApp("Language",[]),[],[[new Terminal("languages'")]]), new Rule(11, new FunApp("Label",[new Arg(0)]),[24],[[new ArgProj(0, 0)]]), new Rule(24, new Arg(0),[26],[[new ArgProj(0, 0)]]), new Rule(24, new Arg(0),[25],[[new ArgProj(0, 0)]]), new Rule(24, new Arg(0),[10],[[new ArgProj(0, 0)]]), new Rule(10, new FunApp("Italian",[]),[],[[new Terminal("Italian")]]), new Rule(9, new FunApp("Italian",[]),[],[[new Terminal("Italian")]]), new Rule(8, new FunApp("Italian",[]),[],[[new Terminal("Italian's")]]), new Rule(7, new FunApp("Italian",[]),[],[[new Terminal("Italian")]]), new Rule(6, new FunApp("Italian",[]),[],[[new Terminal("Italian")]]), new Rule(5, new FunApp("Italian",[]),[],[[new Terminal("Italian's")]]), new Rule(10, new FunApp("Integer_N",[]),[],[[new Terminal("integer")]]), new Rule(9, new FunApp("Integer_N",[]),[],[[new Terminal("integer")]]), new Rule(8, new FunApp("Integer_N",[]),[],[[new Terminal("integer's")]]), new Rule(7, new FunApp("Integer_N",[]),[],[[new Terminal("integers")]]), new Rule(6, new FunApp("Integer_N",[]),[],[[new Terminal("integers")]]), new Rule(5, new FunApp("Integer_N",[]),[],[[new Terminal("integers'")]]), new Rule(23, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(22, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(15, new FunApp("IndefSgDet",[]),[],[[new Terminal("an")]]), new Rule(15, new FunApp("IndefSgDet",[]),[],[[new Terminal("a")]]), new Rule(21, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(23, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(22, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(15, new FunApp("IndefPlDet",[]),[],[[new Terminal("an")]]), new Rule(15, new FunApp("IndefPlDet",[]),[],[[new Terminal("a")]]), new Rule(21, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(10, new FunApp("German",[]),[],[[new Terminal("German")]]), new Rule(9, new FunApp("German",[]),[],[[new Terminal("German")]]), new Rule(8, new FunApp("German",[]),[],[[new Terminal("German's")]]), new Rule(7, new FunApp("German",[]),[],[[new Terminal("German")]]), new Rule(6, new FunApp("German",[]),[],[[new Terminal("German")]]), new Rule(5, new FunApp("German",[]),[],[[new Terminal("German's")]]), new Rule(10, new FunApp("French",[]),[],[[new Terminal("French")]]), new Rule(9, new FunApp("French",[]),[],[[new Terminal("French")]]), new Rule(8, new FunApp("French",[]),[],[[new Terminal("French's")]]), new Rule(7, new FunApp("French",[]),[],[[new Terminal("French")]]), new Rule(6, new FunApp("French",[]),[],[[new Terminal("French")]]), new Rule(5, new FunApp("French",[]),[],[[new Terminal("French's")]]), new Rule(10, new FunApp("Float_N",[]),[],[[new Terminal("float")]]), new Rule(9, new FunApp("Float_N",[]),[],[[new Terminal("float")]]), new Rule(8, new FunApp("Float_N",[]),[],[[new Terminal("float's")]]), new Rule(7, new FunApp("Float_N",[]),[],[[new Terminal("floats")]]), new Rule(6, new FunApp("Float_N",[]),[],[[new Terminal("floats")]]), new Rule(5, new FunApp("Float_N",[]),[],[[new Terminal("floats'")]]), new Rule(10, new FunApp("Finnish",[]),[],[[new Terminal("Finnish")]]), new Rule(9, new FunApp("Finnish",[]),[],[[new Terminal("Finnish")]]), new Rule(8, new FunApp("Finnish",[]),[],[[new Terminal("Finnish's")]]), new Rule(7, new FunApp("Finnish",[]),[],[[new Terminal("Finnish")]]), new Rule(6, new FunApp("Finnish",[]),[],[[new Terminal("Finnish")]]), new Rule(5, new FunApp("Finnish",[]),[],[[new Terminal("Finnish's")]]), new Rule(11, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[4, 14],[[new Terminal("there"), new Terminal("isn't"), new Terminal("an"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(11, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[4, 14],[[new Terminal("there"), new Terminal("isn't"), new Terminal("a"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(11, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[4, 13],[[new Terminal("there"), new Terminal("isn't"), new Terminal("an"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(11, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[4, 13],[[new Terminal("there"), new Terminal("isn't"), new Terminal("a"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(11, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[4, 9],[[new Terminal("there"), new Terminal("isn't"), new Terminal("an"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(11, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[4, 9],[[new Terminal("there"), new Terminal("isn't"), new Terminal("a"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(17, new FunApp("Enter",[]),[],[[new Terminal("Enter")]]), new Rule(20, new FunApp("Enter",[]),[],[[new Terminal("Enters")]]), new Rule(19, new FunApp("Enter",[]),[],[[new Terminal("Entered")]]), new Rule(18, new FunApp("Enter",[]),[],[[new Terminal("Entering")]]), new Rule(10, new FunApp("English",[]),[],[[new Terminal("English")]]), new Rule(9, new FunApp("English",[]),[],[[new Terminal("English")]]), new Rule(8, new FunApp("English",[]),[],[[new Terminal("English's")]]), new Rule(7, new FunApp("English",[]),[],[[new Terminal("English")]]), new Rule(6, new FunApp("English",[]),[],[[new Terminal("English")]]), new Rule(5, new FunApp("English",[]),[],[[new Terminal("English's")]]), new Rule(17, new FunApp("Delete",[]),[],[[new Terminal("Delete")]]), new Rule(20, new FunApp("Delete",[]),[],[[new Terminal("Deletes")]]), new Rule(19, new FunApp("Delete",[]),[],[[new Terminal("Deleted")]]), new Rule(18, new FunApp("Delete",[]),[],[[new Terminal("Deleting")]]), new Rule(23, new FunApp("DefSgDet",[]),[],[[new Terminal("the")]]), new Rule(22, new FunApp("DefSgDet",[]),[],[[new Terminal("the")]]), new Rule(15, new FunApp("DefSgDet",[]),[],[[new Terminal("the")]]), new Rule(21, new FunApp("DefSgDet",[]),[],[[new Terminal("the")]]), new Rule(23, new FunApp("DefPlDet",[]),[],[[new Terminal("the")]]), new Rule(22, new FunApp("DefPlDet",[]),[],[[new Terminal("the")]]), new Rule(15, new FunApp("DefPlDet",[]),[],[[new Terminal("the")]]), new Rule(21, new FunApp("DefPlDet",[]),[],[[new Terminal("the")]]), new Rule(10, new FunApp("Danish",[]),[],[[new Terminal("Danish")]]), new Rule(9, new FunApp("Danish",[]),[],[[new Terminal("Danish")]]), new Rule(8, new FunApp("Danish",[]),[],[[new Terminal("Danish's")]]), new Rule(7, new FunApp("Danish",[]),[],[[new Terminal("Danish")]]), new Rule(6, new FunApp("Danish",[]),[],[[new Terminal("Danish")]]), new Rule(5, new FunApp("Danish",[]),[],[[new Terminal("Danish's")]]), new Rule(17, new FunApp("Cut",[]),[],[[new Terminal("Cut")]]), new Rule(20, new FunApp("Cut",[]),[],[[new Terminal("Cuts")]]), new Rule(19, new FunApp("Cut",[]),[],[[new Terminal("Cuted")]]), new Rule(18, new FunApp("Cut",[]),[],[[new Terminal("Cuting")]]), new Rule(17, new FunApp("Copy",[]),[],[[new Terminal("Copy")]]), new Rule(20, new FunApp("Copy",[]),[],[[new Terminal("Copies")]]), new Rule(19, new FunApp("Copy",[]),[],[[new Terminal("Copied")]]), new Rule(18, new FunApp("Copy",[]),[],[[new Terminal("Copying")]]), new Rule(11, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[17, 15, 4, 14],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(11, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[17, 15, 4, 13],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(11, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[17, 15, 4, 9],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(11, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[16, 15, 4, 14],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("yourself")]]), new Rule(11, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[16, 15, 4, 13],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("yourself")]]), new Rule(11, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[16, 15, 4, 9],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("yourself")]]), new Rule(11, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[17, 15, 12],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(11, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[16, 15, 12],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("yourself")]]), new Rule(12, new Arg(0),[14],[[new ArgProj(0, 0)]]), new Rule(12, new Arg(0),[13],[[new ArgProj(0, 0)]]), new Rule(12, new Arg(0),[9],[[new ArgProj(0, 0)]]), new Rule(10, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgarian")]]), new Rule(9, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgarian")]]), new Rule(8, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgarian's")]]), new Rule(7, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgarian")]]), new Rule(6, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgarian")]]), new Rule(5, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgarian's")]]), new Rule(4, new FunApp("Available",[]),[],[[new Terminal("available")]]), new Rule(3, new FunApp("Available",[]),[],[[new Terminal("availabler")]]), new Rule(2, new FunApp("Available",[]),[],[[new Terminal("availablest")]]), new Rule(1, new FunApp("Available",[]),[],[[new Terminal("availablely")]])],{Adjective:[4, 3, 2, 1], Determiner:[23, 15, 22, 21], Float:[-3], Int:[-2], Noun:[24, 10, 25, 26, 7, 12, 9, 13, 14, 6, 8, 5], Sentence:[11], String:[-1], Verb:[16, 17, 20, 19, 18], _Var:[-4]})), EditorFre: new GFConcrete({coding: "utf8"},{Available: function(cs){return new Arr(new Arr(new Suffix("disponible", new Arr(new Str(""), new Str("s"), new Str(""), new Str("s"), new Str("ment"))), Editor.concretes["EditorFre"].rule("_5", cs), Editor.concretes["EditorFre"].rule("_5", cs)), new Int(1));}, Bulgarian: function(cs){return new Arr(new Suffix("bulgarien", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, Command: function(cs){return new Arr(new Seq(Editor.concretes["EditorFre"].rule("_41", cs), Editor.concretes["EditorFre"].rule("_43", cs), Editor.concretes["EditorFre"].rule("_45", cs), Editor.concretes["EditorFre"].rule("_58", cs)));}, CommandAdj: function(cs){return new Arr(new Seq((new Arr(Editor.concretes["EditorFre"].rule("_68", cs), Editor.concretes["EditorFre"].rule("_69", cs), Editor.concretes["EditorFre"].rule("_70", cs), Editor.concretes["EditorFre"].rule("_71", cs), Editor.concretes["EditorFre"].rule("_72", cs), Editor.concretes["EditorFre"].rule("_73", cs), Editor.concretes["EditorFre"].rule("_68", cs), Editor.concretes["EditorFre"].rule("_69", cs), Editor.concretes["EditorFre"].rule("_70", cs), Editor.concretes["EditorFre"].rule("_71", cs), Editor.concretes["EditorFre"].rule("_72", cs), Editor.concretes["EditorFre"].rule("_73", cs), Editor.concretes["EditorFre"].rule("_67", cs), Editor.concretes["EditorFre"].rule("_67", cs))).sel(Editor.concretes["EditorFre"].rule("_40", cs)), Editor.concretes["EditorFre"].rule("_43", cs), Editor.concretes["EditorFre"].rule("_45", cs),(new Arr(new Arr(Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_87", cs)), new Arr(Editor.concretes["EditorFre"].rule("_87", cs), Editor.concretes["EditorFre"].rule("_87", cs)))).sel(Editor.concretes["EditorFre"].rule("_25", cs)).sel(Editor.concretes["EditorFre"].rule("_27", cs))));}, Copy: function(cs){return new Arr(new Suffix("copi", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Cut: function(cs){return new Arr(new Suffix("coup", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Danish: function(cs){return new Arr(new Suffix("danois", Editor.concretes["EditorFre"].rule("_100", cs)), new Int(0));}, DefPlDet: function(cs){return Editor.concretes["EditorFre"].rule("_112", cs);}, DefSgDet: function(cs){return Editor.concretes["EditorFre"].rule("_112", cs);}, Delete: function(cs){return new Arr(new Suffix("enlev", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, English: function(cs){return new Arr(new Suffix("anglais", Editor.concretes["EditorFre"].rule("_100", cs)), new Int(0));}, Enter: function(cs){return new Arr(new Suffix("introdui", new Arr(new Str("re"), new Str("re"), new Str("s"), new Str("s"), new Str("t"), new Str("sons"), new Str("sez"), new Str("sent"), new Str("se"), new Str("ses"), new Str("se"), new Str("sions"), new Str("siez"), new Str("sent"), new Str("s"), new Str("sons"), new Str("sez"), new Str("t"), new Str("ts"), new Str("te"), new Str("tes"), new Str("sant"))), new Int(0));}, ErrorMessage: function(cs){return new Arr(new Seq(new Str("il"), new Str("ne"), new Str("y"), new Str("a"), new Str("pas"),(new Arr(new Str("des"), new Str("des"))).sel(Editor.concretes["EditorFre"].rule("_121", cs)),(new Arr(new Seq(Editor.concretes["EditorFre"].rule("_125", cs), Editor.concretes["EditorFre"].rule("_47", cs)), new Seq(Editor.concretes["EditorFre"].rule("_47", cs), Editor.concretes["EditorFre"].rule("_125", cs)))).sel(Editor.concretes["EditorFre"].rule("_18", cs))));}, Finnish: function(cs){return new Arr(new Suffix("finnois", Editor.concretes["EditorFre"].rule("_100", cs)), new Int(0));}, Float_N: function(cs){return new Arr(new Suffix("réel", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, French: function(cs){return new Arr(new Suffix("français", Editor.concretes["EditorFre"].rule("_100", cs)), new Int(0));}, German: function(cs){return new Arr(new Suffix("allemand", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, IndefPlDet: function(cs){return Editor.concretes["EditorFre"].rule("_155", cs);}, IndefSgDet: function(cs){return Editor.concretes["EditorFre"].rule("_155", cs);}, Integer_N: function(cs){return new Arr(new Suffix("entier", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, Italian: function(cs){return new Arr(new Suffix("italien", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, Label: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_43", cs));}, Language: function(cs){return new Arr(new Suffix("langue", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(1));}, Next: function(cs){return new Arr(new Arr(new Suffix("prochain", Editor.concretes["EditorFre"].rule("_163", cs)), Editor.concretes["EditorFre"].rule("_170", cs), Editor.concretes["EditorFre"].rule("_170", cs)), new Int(1));}, Node: function(cs){return new Arr(new Suffix("noeud", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, Norwegian: function(cs){return new Arr(new Suffix("norvégien", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, Page: function(cs){return new Arr(new Suffix("page", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(1));}, Parse: function(cs){return new Arr(new Suffix("analys", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Paste: function(cs){return new Arr(new Suffix("coll", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Previous: function(cs){return new Arr(new Arr(new Suffix("précédent", Editor.concretes["EditorFre"].rule("_163", cs)), Editor.concretes["EditorFre"].rule("_189", cs), Editor.concretes["EditorFre"].rule("_189", cs)), new Int(1));}, RandomlyCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorFre"].rule("_41", cs), Editor.concretes["EditorFre"].rule("_43", cs), Editor.concretes["EditorFre"].rule("_45", cs), Editor.concretes["EditorFre"].rule("_58", cs), new Str("aléatoirement")));}, Redo: function(cs){return new Arr(new Suffix("ref", new Arr(new Str("aire"), new Str("aire"), new Str("ais"), new Str("ais"), new Str("ait"), new Str("aisons"), new Str("aites"), new Str("ont"), new Str("asse"), new Str("asses"), new Str("asse"), new Str("assions"), new Str("assiez"), new Str("assent"), new Str("ais"), new Str("aisons"), new Str("aites"), new Str("ait"), new Str("aits"), new Str("aite"), new Str("aites"), new Str("aisant"))), new Int(0));}, Refine: function(cs){return new Arr(new Suffix("raffin", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Refinement: function(cs){return new Arr(new Suffix("raffinement", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, Replace: function(cs){return new Arr(new Suffix("rempla", new Arr(new Str("cer"), new Str("cer"), new Str("ce"), new Str("ces"), new Str("ce"), new Str("çons"), new Str("cez"), new Str("cent"), new Str("ce"), new Str("ces"), new Str("ce"), new Str("cions"), new Str("ciez"), new Str("cent"), new Str("ce"), new Str("çons"), new Str("cez"), new Str("cé"), new Str("cés"), new Str("cée"), new Str("cées"), new Str("çant"))), new Int(0));}, Russian: function(cs){return new Arr(new Suffix("russe", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(1));}, Select: function(cs){return new Arr(new Suffix("selectionn", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Show: function(cs){return new Arr(new Suffix("montr", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, SingleWordCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorFre"].rule("_12", cs).sel(Editor.concretes["EditorFre"].rule("_20", cs)), Editor.concretes["EditorFre"].rule("_43", cs)));}, Spanish: function(cs){return new Arr(new Suffix("espagnol", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, String_N: function(cs){return new Arr(new Arr(new Seq(new Str("chaîne"), new Str("de"), new Str("charactères")), new Seq(new Str("chaînes"), new Str("de"), new Str("charactères"))), new Int(1));}, Swedish: function(cs){return new Arr(new Suffix("suédois", Editor.concretes["EditorFre"].rule("_100", cs)), new Int(0));}, Tree: function(cs){return new Arr(new Suffix("arbre", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(0));}, Undo: function(cs){return new Arr(new Suffix("annul", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Wrap: function(cs){return new Arr(new Suffix("emball", Editor.concretes["EditorFre"].rule("_95", cs)), new Int(0));}, Wrapper: function(cs){return new Arr(new Suffix("emballage", Editor.concretes["EditorFre"].rule("_8", cs)), new Int(1));}, _100: function(cs){return new Arr(new Str(""), new Str(""));}, _103: function(cs){return new Arr(new Str("le"), new Str("le"), new Str("du"), new Str("au"), new Str("le"));}, _104: function(cs){return new Seq(new Str("de"), new Str("la"));}, _105: function(cs){return new Seq(new Str("Ã"), new Str("la"));}, _106: function(cs){return new Arr(new Str("la"), new Str("la"), Editor.concretes["EditorFre"].rule("_104", cs), Editor.concretes["EditorFre"].rule("_105", cs), new Str("la"));}, _107: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_103", cs), Editor.concretes["EditorFre"].rule("_106", cs));}, _108: function(cs){return new Arr(new Str("les"), new Str("les"), new Str("des"), new Str("aux"), new Str("les"));}, _109: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_108", cs), Editor.concretes["EditorFre"].rule("_108", cs));}, _11: function(cs){return new Seq();}, _110: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_107", cs), Editor.concretes["EditorFre"].rule("_109", cs));}, _111: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_110", cs), Editor.concretes["EditorFre"].rule("_110", cs));}, _112: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_111", cs));}, _12: function(cs){return new Arr(new Str("me"), new Str("te"), new Str("le"), new Str("nous"), new Str("vous"), new Str("les"), new Str("me"), new Str("te"), new Str("la"), new Str("nous"), new Str("vous"), new Str("les"), new Str("se"), Editor.concretes["EditorFre"].rule("_11", cs));}, _121: function(cs){return cs[1].sel(new Int(1));}, _123: function(cs){return new Arr(new Int(1), new Int(3));}, _124: function(cs){return Editor.concretes["EditorFre"].rule("_123", cs).sel(Editor.concretes["EditorFre"].rule("_121", cs));}, _125: function(cs){return Editor.concretes["EditorFre"].rule("_43", cs).sel(Editor.concretes["EditorFre"].rule("_124", cs));}, _13: function(cs){return new Arr(new Int(2), new Int(8));}, _14: function(cs){return cs[2].sel(new Int(1));}, _140: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs));}, _141: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_140", cs), Editor.concretes["EditorFre"].rule("_140", cs));}, _142: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_141", cs), Editor.concretes["EditorFre"].rule("_141", cs));}, _143: function(cs){return new Seq(new Str("d'"), new Str("un"));}, _144: function(cs){return new Seq(new Str("Ã"), new Str("un"));}, _145: function(cs){return new Arr(new Str("un"), new Str("un"), Editor.concretes["EditorFre"].rule("_143", cs), Editor.concretes["EditorFre"].rule("_144", cs), new Str("un"));}, _146: function(cs){return new Seq(new Str("d'"), new Str("une"));}, _147: function(cs){return new Seq(new Str("Ã"), new Str("une"));}, _148: function(cs){return new Arr(new Str("une"), new Str("une"), Editor.concretes["EditorFre"].rule("_146", cs), Editor.concretes["EditorFre"].rule("_147", cs), new Str("une"));}, _149: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_145", cs), Editor.concretes["EditorFre"].rule("_148", cs));}, _15: function(cs){return Editor.concretes["EditorFre"].rule("_13", cs).sel(Editor.concretes["EditorFre"].rule("_14", cs));}, _150: function(cs){return new Seq(new Str("Ã"), new Str("des"));}, _151: function(cs){return new Arr(new Str("des"), new Str("des"), new Str("de"), Editor.concretes["EditorFre"].rule("_150", cs), new Str("des"));}, _152: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_151", cs), Editor.concretes["EditorFre"].rule("_151", cs));}, _153: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_149", cs), Editor.concretes["EditorFre"].rule("_152", cs));}, _154: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_142", cs), Editor.concretes["EditorFre"].rule("_153", cs));}, _155: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_154", cs));}, _16: function(cs){return new Arr(new Int(12), new Int(13));}, _163: function(cs){return new Arr(new Str(""), new Str("s"), new Str("e"), new Str("es"), new Str("ement"));}, _165: function(cs){return new Seq(new Str("plus"), new Str("prochain"));}, _166: function(cs){return new Seq(new Str("plus"), new Str("prochains"));}, _167: function(cs){return new Seq(new Str("plus"), new Str("prochaine"));}, _168: function(cs){return new Seq(new Str("plus"), new Str("prochaines"));}, _169: function(cs){return new Seq(new Str("plus"), new Str("prochainement"));}, _17: function(cs){return new Arr(new Int(1), new Int(1), new Int(0));}, _170: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_165", cs), Editor.concretes["EditorFre"].rule("_166", cs), Editor.concretes["EditorFre"].rule("_167", cs), Editor.concretes["EditorFre"].rule("_168", cs), Editor.concretes["EditorFre"].rule("_169", cs));}, _18: function(cs){return cs[0].sel(new Int(1));}, _184: function(cs){return new Seq(new Str("plus"), new Str("précédent"));}, _185: function(cs){return new Seq(new Str("plus"), new Str("précédents"));}, _186: function(cs){return new Seq(new Str("plus"), new Str("précédente"));}, _187: function(cs){return new Seq(new Str("plus"), new Str("précédentes"));}, _188: function(cs){return new Seq(new Str("plus"), new Str("précédentement"));}, _189: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_184", cs), Editor.concretes["EditorFre"].rule("_185", cs), Editor.concretes["EditorFre"].rule("_186", cs), Editor.concretes["EditorFre"].rule("_187", cs), Editor.concretes["EditorFre"].rule("_188", cs));}, _19: function(cs){return Editor.concretes["EditorFre"].rule("_17", cs).sel(Editor.concretes["EditorFre"].rule("_18", cs));}, _2: function(cs){return new Seq(new Str("plus"), new Str("disponible"));}, _20: function(cs){return Editor.concretes["EditorFre"].rule("_16", cs).sel(Editor.concretes["EditorFre"].rule("_19", cs));}, _21: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_15", cs), Editor.concretes["EditorFre"].rule("_20", cs));}, _22: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_20", cs), Editor.concretes["EditorFre"].rule("_20", cs));}, _229: function(cs){return new Arr(cs[0], cs[0], cs[0], cs[0], cs[0]);}, _23: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_21", cs), Editor.concretes["EditorFre"].rule("_22", cs));}, _232: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_229", cs), Editor.concretes["EditorFre"].rule("_229", cs));}, _233: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_232", cs), Editor.concretes["EditorFre"].rule("_232", cs));}, _24: function(cs){return new Arr(new Int(1), new Int(0));}, _25: function(cs){return Editor.concretes["EditorFre"].rule("_24", cs).sel(new Int(0));}, _26: function(cs){return Editor.concretes["EditorFre"].rule("_23", cs).sel(Editor.concretes["EditorFre"].rule("_25", cs));}, _27: function(cs){return Editor.concretes["EditorFre"].rule("_24", cs).sel(new Int(1));}, _28: function(cs){return Editor.concretes["EditorFre"].rule("_26", cs).sel(Editor.concretes["EditorFre"].rule("_27", cs));}, _29: function(cs){return Editor.concretes["EditorFre"].rule("_12", cs).sel(Editor.concretes["EditorFre"].rule("_28", cs));}, _3: function(cs){return new Seq(new Str("plus"), new Str("disponibles"));}, _30: function(cs){return new Seq(new Str("me"), Editor.concretes["EditorFre"].rule("_29", cs));}, _31: function(cs){return new Seq(new Str("te"), Editor.concretes["EditorFre"].rule("_29", cs));}, _32: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_29", cs), new Str("lui"));}, _33: function(cs){return new Seq(new Str("nous"), Editor.concretes["EditorFre"].rule("_29", cs));}, _34: function(cs){return new Seq(new Str("vous"), Editor.concretes["EditorFre"].rule("_29", cs));}, _35: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_29", cs), new Str("leur"));}, _36: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_30", cs), Editor.concretes["EditorFre"].rule("_31", cs), Editor.concretes["EditorFre"].rule("_32", cs), Editor.concretes["EditorFre"].rule("_33", cs), Editor.concretes["EditorFre"].rule("_34", cs), Editor.concretes["EditorFre"].rule("_35", cs), Editor.concretes["EditorFre"].rule("_30", cs), Editor.concretes["EditorFre"].rule("_31", cs), Editor.concretes["EditorFre"].rule("_32", cs), Editor.concretes["EditorFre"].rule("_33", cs), Editor.concretes["EditorFre"].rule("_34", cs), Editor.concretes["EditorFre"].rule("_35", cs), Editor.concretes["EditorFre"].rule("_29", cs), Editor.concretes["EditorFre"].rule("_29", cs));}, _37: function(cs){return new Arr(new Int(13), new Int(13));}, _38: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_37", cs), Editor.concretes["EditorFre"].rule("_37", cs));}, _39: function(cs){return Editor.concretes["EditorFre"].rule("_38", cs).sel(Editor.concretes["EditorFre"].rule("_25", cs));}, _4: function(cs){return new Seq(new Str("plus"), new Str("disponiblement"));}, _40: function(cs){return Editor.concretes["EditorFre"].rule("_39", cs).sel(Editor.concretes["EditorFre"].rule("_27", cs));}, _41: function(cs){return Editor.concretes["EditorFre"].rule("_36", cs).sel(Editor.concretes["EditorFre"].rule("_40", cs));}, _42: function(cs){return cs[0].sel(new Int(0));}, _43: function(cs){return Editor.concretes["EditorFre"].rule("_42", cs).sel(new Int(0));}, _44: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_11", cs));}, _45: function(cs){return Editor.concretes["EditorFre"].rule("_44", cs).sel(Editor.concretes["EditorFre"].rule("_40", cs));}, _46: function(cs){return cs[1].sel(new Int(0));}, _47: function(cs){return Editor.concretes["EditorFre"].rule("_46", cs).sel(new Int(1));}, _48: function(cs){return Editor.concretes["EditorFre"].rule("_47", cs).sel(new Int(0));}, _49: function(cs){return Editor.concretes["EditorFre"].rule("_48", cs).sel(Editor.concretes["EditorFre"].rule("_14", cs));}, _5: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_2", cs), Editor.concretes["EditorFre"].rule("_3", cs), Editor.concretes["EditorFre"].rule("_2", cs), Editor.concretes["EditorFre"].rule("_3", cs), Editor.concretes["EditorFre"].rule("_4", cs));}, _50: function(cs){return Editor.concretes["EditorFre"].rule("_49", cs).sel(new Int(1));}, _51: function(cs){return cs[2].sel(new Int(0));}, _52: function(cs){return Editor.concretes["EditorFre"].rule("_51", cs).sel(new Int(0));}, _53: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_50", cs), Editor.concretes["EditorFre"].rule("_52", cs));}, _54: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_11", cs), Editor.concretes["EditorFre"].rule("_53", cs));}, _55: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_53", cs), Editor.concretes["EditorFre"].rule("_53", cs));}, _56: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_54", cs), Editor.concretes["EditorFre"].rule("_55", cs));}, _57: function(cs){return Editor.concretes["EditorFre"].rule("_56", cs).sel(Editor.concretes["EditorFre"].rule("_25", cs));}, _58: function(cs){return Editor.concretes["EditorFre"].rule("_57", cs).sel(Editor.concretes["EditorFre"].rule("_27", cs));}, _61: function(cs){return cs[3].sel(new Int(1));}, _62: function(cs){return Editor.concretes["EditorFre"].rule("_13", cs).sel(Editor.concretes["EditorFre"].rule("_61", cs));}, _63: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_62", cs), Editor.concretes["EditorFre"].rule("_20", cs));}, _64: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_63", cs), Editor.concretes["EditorFre"].rule("_22", cs));}, _65: function(cs){return Editor.concretes["EditorFre"].rule("_64", cs).sel(Editor.concretes["EditorFre"].rule("_25", cs));}, _66: function(cs){return Editor.concretes["EditorFre"].rule("_65", cs).sel(Editor.concretes["EditorFre"].rule("_27", cs));}, _67: function(cs){return Editor.concretes["EditorFre"].rule("_12", cs).sel(Editor.concretes["EditorFre"].rule("_66", cs));}, _68: function(cs){return new Seq(new Str("me"), Editor.concretes["EditorFre"].rule("_67", cs));}, _69: function(cs){return new Seq(new Str("te"), Editor.concretes["EditorFre"].rule("_67", cs));}, _70: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_67", cs), new Str("lui"));}, _71: function(cs){return new Seq(new Str("nous"), Editor.concretes["EditorFre"].rule("_67", cs));}, _72: function(cs){return new Seq(new Str("vous"), Editor.concretes["EditorFre"].rule("_67", cs));}, _73: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_67", cs), new Str("leur"));}, _76: function(cs){return Editor.concretes["EditorFre"].rule("_48", cs).sel(Editor.concretes["EditorFre"].rule("_61", cs));}, _77: function(cs){return Editor.concretes["EditorFre"].rule("_76", cs).sel(new Int(1));}, _78: function(cs){return new Arr(new Int(0), new Int(2));}, _79: function(cs){return Editor.concretes["EditorFre"].rule("_78", cs).sel(Editor.concretes["EditorFre"].rule("_61", cs));}, _8: function(cs){return new Arr(new Str(""), new Str("s"));}, _80: function(cs){return Editor.concretes["EditorFre"].rule("_52", cs).sel(Editor.concretes["EditorFre"].rule("_79", cs));}, _81: function(cs){return cs[3].sel(new Int(0));}, _82: function(cs){return Editor.concretes["EditorFre"].rule("_81", cs).sel(new Int(0));}, _83: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_80", cs), Editor.concretes["EditorFre"].rule("_82", cs));}, _84: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_82", cs), Editor.concretes["EditorFre"].rule("_80", cs));}, _85: function(cs){return new Arr(Editor.concretes["EditorFre"].rule("_83", cs), Editor.concretes["EditorFre"].rule("_84", cs));}, _86: function(cs){return Editor.concretes["EditorFre"].rule("_85", cs).sel(Editor.concretes["EditorFre"].rule("_14", cs));}, _87: function(cs){return new Seq(Editor.concretes["EditorFre"].rule("_77", cs), Editor.concretes["EditorFre"].rule("_86", cs));}, _95: function(cs){return new Arr(new Str("er"), new Str("er"), new Str("e"), new Str("es"), new Str("e"), new Str("ons"), new Str("ez"), new Str("ent"), new Str("e"), new Str("es"), new Str("e"), new Str("ions"), new Str("iez"), new Str("ent"), new Str("e"), new Str("ons"), new Str("ez"), new Str("é"), new Str("és"), new Str("ée"), new Str("ées"), new Str("ant"));}, Adjective: function(cs){return new Arr(new Arr(Editor.concretes["EditorFre"].rule("_229", cs), Editor.concretes["EditorFre"].rule("_229", cs), Editor.concretes["EditorFre"].rule("_229", cs)), new Int(0));}, Determiner: function(cs){return new Arr(new Arr(Editor.concretes["EditorFre"].rule("_233", cs), Editor.concretes["EditorFre"].rule("_233", cs)));}, Noun: function(cs){return new Arr(new Arr(cs[0], cs[0]), new Int(0));}, Sentence: function(cs){return new Arr(cs[0]);}, Verb: function(cs){return new Arr(new Arr(cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0]), new Int(0));}, "Int": function(cs){return new Arr(cs[0]);}, "Float": function(cs){return new Arr(cs[0]);}, "String": function(cs){return new Arr(cs[0]);}}, new Parser("Sentence",[new Rule(23, new FunApp("Wrapper",[]),[],[[new Terminal("emballage")]]), new Rule(87, new FunApp("Wrapper",[]),[],[[new Terminal("emballages")]]), new Rule(20, new FunApp("Wrap",[]),[],[[new Terminal("emballer")]]), new Rule(47, new FunApp("Wrap",[]),[],[[new Terminal("emballer")]]), new Rule(46, new FunApp("Wrap",[]),[],[[new Terminal("emballe")]]), new Rule(45, new FunApp("Wrap",[]),[],[[new Terminal("emballes")]]), new Rule(44, new FunApp("Wrap",[]),[],[[new Terminal("emballe")]]), new Rule(43, new FunApp("Wrap",[]),[],[[new Terminal("emballons")]]), new Rule(42, new FunApp("Wrap",[]),[],[[new Terminal("emballez")]]), new Rule(41, new FunApp("Wrap",[]),[],[[new Terminal("emballent")]]), new Rule(40, new FunApp("Wrap",[]),[],[[new Terminal("emballe")]]), new Rule(39, new FunApp("Wrap",[]),[],[[new Terminal("emballes")]]), new Rule(38, new FunApp("Wrap",[]),[],[[new Terminal("emballe")]]), new Rule(37, new FunApp("Wrap",[]),[],[[new Terminal("emballions")]]), new Rule(36, new FunApp("Wrap",[]),[],[[new Terminal("emballiez")]]), new Rule(35, new FunApp("Wrap",[]),[],[[new Terminal("emballent")]]), new Rule(34, new FunApp("Wrap",[]),[],[[new Terminal("emballe")]]), new Rule(33, new FunApp("Wrap",[]),[],[[new Terminal("emballons")]]), new Rule(32, new FunApp("Wrap",[]),[],[[new Terminal("emballez")]]), new Rule(31, new FunApp("Wrap",[]),[],[[new Terminal("emballé")]]), new Rule(30, new FunApp("Wrap",[]),[],[[new Terminal("emballés")]]), new Rule(29, new FunApp("Wrap",[]),[],[[new Terminal("emballée")]]), new Rule(28, new FunApp("Wrap",[]),[],[[new Terminal("emballées")]]), new Rule(27, new FunApp("Wrap",[]),[],[[new Terminal("emballant")]]), new Rule(20, new FunApp("Undo",[]),[],[[new Terminal("annuler")]]), new Rule(47, new FunApp("Undo",[]),[],[[new Terminal("annuler")]]), new Rule(46, new FunApp("Undo",[]),[],[[new Terminal("annule")]]), new Rule(45, new FunApp("Undo",[]),[],[[new Terminal("annules")]]), new Rule(44, new FunApp("Undo",[]),[],[[new Terminal("annule")]]), new Rule(43, new FunApp("Undo",[]),[],[[new Terminal("annulons")]]), new Rule(42, new FunApp("Undo",[]),[],[[new Terminal("annulez")]]), new Rule(41, new FunApp("Undo",[]),[],[[new Terminal("annulent")]]), new Rule(40, new FunApp("Undo",[]),[],[[new Terminal("annule")]]), new Rule(39, new FunApp("Undo",[]),[],[[new Terminal("annules")]]), new Rule(38, new FunApp("Undo",[]),[],[[new Terminal("annule")]]), new Rule(37, new FunApp("Undo",[]),[],[[new Terminal("annulions")]]), new Rule(36, new FunApp("Undo",[]),[],[[new Terminal("annuliez")]]), new Rule(35, new FunApp("Undo",[]),[],[[new Terminal("annulent")]]), new Rule(34, new FunApp("Undo",[]),[],[[new Terminal("annule")]]), new Rule(33, new FunApp("Undo",[]),[],[[new Terminal("annulons")]]), new Rule(32, new FunApp("Undo",[]),[],[[new Terminal("annulez")]]), new Rule(31, new FunApp("Undo",[]),[],[[new Terminal("annulé")]]), new Rule(30, new FunApp("Undo",[]),[],[[new Terminal("annulés")]]), new Rule(29, new FunApp("Undo",[]),[],[[new Terminal("annulée")]]), new Rule(28, new FunApp("Undo",[]),[],[[new Terminal("annulées")]]), new Rule(27, new FunApp("Undo",[]),[],[[new Terminal("annulant")]]), new Rule(17, new FunApp("Tree",[]),[],[[new Terminal("arbre")]]), new Rule(16, new FunApp("Tree",[]),[],[[new Terminal("arbres")]]), new Rule(17, new FunApp("Swedish",[]),[],[[new Terminal("suédois")]]), new Rule(16, new FunApp("Swedish",[]),[],[[new Terminal("suédois")]]), new Rule(23, new FunApp("String_N",[]),[],[[new Terminal("chaîne"), new Terminal("de"), new Terminal("charactères")]]), new Rule(87, new FunApp("String_N",[]),[],[[new Terminal("chaînes"), new Terminal("de"), new Terminal("charactères")]]), new Rule(17, new FunApp("Spanish",[]),[],[[new Terminal("espagnol")]]), new Rule(16, new FunApp("Spanish",[]),[],[[new Terminal("espagnols")]]), new Rule(18, new FunApp("SingleWordCommand",[new Arg(0)]),[22],[[new Terminal("s'"), new ArgProj(0, 0)]]), new Rule(18, new FunApp("SingleWordCommand",[new Arg(0)]),[22],[[new Terminal("se"), new ArgProj(0, 0)]]), new Rule(18, new FunApp("SingleWordCommand",[new Arg(0)]),[21],[[new ArgProj(0, 0)]]), new Rule(18, new FunApp("SingleWordCommand",[new Arg(0)]),[20],[[new ArgProj(0, 0)]]), new Rule(20, new FunApp("Show",[]),[],[[new Terminal("montrer")]]), new Rule(47, new FunApp("Show",[]),[],[[new Terminal("montrer")]]), new Rule(46, new FunApp("Show",[]),[],[[new Terminal("montre")]]), new Rule(45, new FunApp("Show",[]),[],[[new Terminal("montres")]]), new Rule(44, new FunApp("Show",[]),[],[[new Terminal("montre")]]), new Rule(43, new FunApp("Show",[]),[],[[new Terminal("montrons")]]), new Rule(42, new FunApp("Show",[]),[],[[new Terminal("montrez")]]), new Rule(41, new FunApp("Show",[]),[],[[new Terminal("montrent")]]), new Rule(40, new FunApp("Show",[]),[],[[new Terminal("montre")]]), new Rule(39, new FunApp("Show",[]),[],[[new Terminal("montres")]]), new Rule(38, new FunApp("Show",[]),[],[[new Terminal("montre")]]), new Rule(37, new FunApp("Show",[]),[],[[new Terminal("montrions")]]), new Rule(36, new FunApp("Show",[]),[],[[new Terminal("montriez")]]), new Rule(35, new FunApp("Show",[]),[],[[new Terminal("montrent")]]), new Rule(34, new FunApp("Show",[]),[],[[new Terminal("montre")]]), new Rule(33, new FunApp("Show",[]),[],[[new Terminal("montrons")]]), new Rule(32, new FunApp("Show",[]),[],[[new Terminal("montrez")]]), new Rule(31, new FunApp("Show",[]),[],[[new Terminal("montré")]]), new Rule(30, new FunApp("Show",[]),[],[[new Terminal("montrés")]]), new Rule(29, new FunApp("Show",[]),[],[[new Terminal("montrée")]]), new Rule(28, new FunApp("Show",[]),[],[[new Terminal("montrées")]]), new Rule(27, new FunApp("Show",[]),[],[[new Terminal("montrant")]]), new Rule(20, new FunApp("Select",[]),[],[[new Terminal("selectionner")]]), new Rule(47, new FunApp("Select",[]),[],[[new Terminal("selectionner")]]), new Rule(46, new FunApp("Select",[]),[],[[new Terminal("selectionne")]]), new Rule(45, new FunApp("Select",[]),[],[[new Terminal("selectionnes")]]), new Rule(44, new FunApp("Select",[]),[],[[new Terminal("selectionne")]]), new Rule(43, new FunApp("Select",[]),[],[[new Terminal("selectionnons")]]), new Rule(42, new FunApp("Select",[]),[],[[new Terminal("selectionnez")]]), new Rule(41, new FunApp("Select",[]),[],[[new Terminal("selectionnent")]]), new Rule(40, new FunApp("Select",[]),[],[[new Terminal("selectionne")]]), new Rule(39, new FunApp("Select",[]),[],[[new Terminal("selectionnes")]]), new Rule(38, new FunApp("Select",[]),[],[[new Terminal("selectionne")]]), new Rule(37, new FunApp("Select",[]),[],[[new Terminal("selectionnions")]]), new Rule(36, new FunApp("Select",[]),[],[[new Terminal("selectionniez")]]), new Rule(35, new FunApp("Select",[]),[],[[new Terminal("selectionnent")]]), new Rule(34, new FunApp("Select",[]),[],[[new Terminal("selectionne")]]), new Rule(33, new FunApp("Select",[]),[],[[new Terminal("selectionnons")]]), new Rule(32, new FunApp("Select",[]),[],[[new Terminal("selectionnez")]]), new Rule(31, new FunApp("Select",[]),[],[[new Terminal("selectionné")]]), new Rule(30, new FunApp("Select",[]),[],[[new Terminal("selectionnés")]]), new Rule(29, new FunApp("Select",[]),[],[[new Terminal("selectionnée")]]), new Rule(28, new FunApp("Select",[]),[],[[new Terminal("selectionnées")]]), new Rule(27, new FunApp("Select",[]),[],[[new Terminal("selectionnant")]]), new Rule(23, new FunApp("Russian",[]),[],[[new Terminal("russe")]]), new Rule(87, new FunApp("Russian",[]),[],[[new Terminal("russes")]]), new Rule(20, new FunApp("Replace",[]),[],[[new Terminal("remplacer")]]), new Rule(47, new FunApp("Replace",[]),[],[[new Terminal("remplacer")]]), new Rule(46, new FunApp("Replace",[]),[],[[new Terminal("remplace")]]), new Rule(45, new FunApp("Replace",[]),[],[[new Terminal("remplaces")]]), new Rule(44, new FunApp("Replace",[]),[],[[new Terminal("remplace")]]), new Rule(43, new FunApp("Replace",[]),[],[[new Terminal("remplaçons")]]), new Rule(42, new FunApp("Replace",[]),[],[[new Terminal("remplacez")]]), new Rule(41, new FunApp("Replace",[]),[],[[new Terminal("remplacent")]]), new Rule(40, new FunApp("Replace",[]),[],[[new Terminal("remplace")]]), new Rule(39, new FunApp("Replace",[]),[],[[new Terminal("remplaces")]]), new Rule(38, new FunApp("Replace",[]),[],[[new Terminal("remplace")]]), new Rule(37, new FunApp("Replace",[]),[],[[new Terminal("remplacions")]]), new Rule(36, new FunApp("Replace",[]),[],[[new Terminal("remplaciez")]]), new Rule(35, new FunApp("Replace",[]),[],[[new Terminal("remplacent")]]), new Rule(34, new FunApp("Replace",[]),[],[[new Terminal("remplace")]]), new Rule(33, new FunApp("Replace",[]),[],[[new Terminal("remplaçons")]]), new Rule(32, new FunApp("Replace",[]),[],[[new Terminal("remplacez")]]), new Rule(31, new FunApp("Replace",[]),[],[[new Terminal("remplacé")]]), new Rule(30, new FunApp("Replace",[]),[],[[new Terminal("remplacés")]]), new Rule(29, new FunApp("Replace",[]),[],[[new Terminal("remplacée")]]), new Rule(28, new FunApp("Replace",[]),[],[[new Terminal("remplacées")]]), new Rule(27, new FunApp("Replace",[]),[],[[new Terminal("remplaçant")]]), new Rule(17, new FunApp("Refinement",[]),[],[[new Terminal("raffinement")]]), new Rule(16, new FunApp("Refinement",[]),[],[[new Terminal("raffinements")]]), new Rule(20, new FunApp("Refine",[]),[],[[new Terminal("raffiner")]]), new Rule(47, new FunApp("Refine",[]),[],[[new Terminal("raffiner")]]), new Rule(46, new FunApp("Refine",[]),[],[[new Terminal("raffine")]]), new Rule(45, new FunApp("Refine",[]),[],[[new Terminal("raffines")]]), new Rule(44, new FunApp("Refine",[]),[],[[new Terminal("raffine")]]), new Rule(43, new FunApp("Refine",[]),[],[[new Terminal("raffinons")]]), new Rule(42, new FunApp("Refine",[]),[],[[new Terminal("raffinez")]]), new Rule(41, new FunApp("Refine",[]),[],[[new Terminal("raffinent")]]), new Rule(40, new FunApp("Refine",[]),[],[[new Terminal("raffine")]]), new Rule(39, new FunApp("Refine",[]),[],[[new Terminal("raffines")]]), new Rule(38, new FunApp("Refine",[]),[],[[new Terminal("raffine")]]), new Rule(37, new FunApp("Refine",[]),[],[[new Terminal("raffinions")]]), new Rule(36, new FunApp("Refine",[]),[],[[new Terminal("raffiniez")]]), new Rule(35, new FunApp("Refine",[]),[],[[new Terminal("raffinent")]]), new Rule(34, new FunApp("Refine",[]),[],[[new Terminal("raffine")]]), new Rule(33, new FunApp("Refine",[]),[],[[new Terminal("raffinons")]]), new Rule(32, new FunApp("Refine",[]),[],[[new Terminal("raffinez")]]), new Rule(31, new FunApp("Refine",[]),[],[[new Terminal("raffiné")]]), new Rule(30, new FunApp("Refine",[]),[],[[new Terminal("raffinés")]]), new Rule(29, new FunApp("Refine",[]),[],[[new Terminal("raffinée")]]), new Rule(28, new FunApp("Refine",[]),[],[[new Terminal("raffinées")]]), new Rule(27, new FunApp("Refine",[]),[],[[new Terminal("raffinant")]]), new Rule(20, new FunApp("Redo",[]),[],[[new Terminal("refaire")]]), new Rule(47, new FunApp("Redo",[]),[],[[new Terminal("refaire")]]), new Rule(46, new FunApp("Redo",[]),[],[[new Terminal("refais")]]), new Rule(45, new FunApp("Redo",[]),[],[[new Terminal("refais")]]), new Rule(44, new FunApp("Redo",[]),[],[[new Terminal("refait")]]), new Rule(43, new FunApp("Redo",[]),[],[[new Terminal("refaisons")]]), new Rule(42, new FunApp("Redo",[]),[],[[new Terminal("refaites")]]), new Rule(41, new FunApp("Redo",[]),[],[[new Terminal("refont")]]), new Rule(40, new FunApp("Redo",[]),[],[[new Terminal("refasse")]]), new Rule(39, new FunApp("Redo",[]),[],[[new Terminal("refasses")]]), new Rule(38, new FunApp("Redo",[]),[],[[new Terminal("refasse")]]), new Rule(37, new FunApp("Redo",[]),[],[[new Terminal("refassions")]]), new Rule(36, new FunApp("Redo",[]),[],[[new Terminal("refassiez")]]), new Rule(35, new FunApp("Redo",[]),[],[[new Terminal("refassent")]]), new Rule(34, new FunApp("Redo",[]),[],[[new Terminal("refais")]]), new Rule(33, new FunApp("Redo",[]),[],[[new Terminal("refaisons")]]), new Rule(32, new FunApp("Redo",[]),[],[[new Terminal("refaites")]]), new Rule(31, new FunApp("Redo",[]),[],[[new Terminal("refait")]]), new Rule(30, new FunApp("Redo",[]),[],[[new Terminal("refaits")]]), new Rule(29, new FunApp("Redo",[]),[],[[new Terminal("refaite")]]), new Rule(28, new FunApp("Redo",[]),[],[[new Terminal("refaites")]]), new Rule(27, new FunApp("Redo",[]),[],[[new Terminal("refaisant")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[22, 24, 23],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[22, 24, 23],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[21, 24, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[20, 24, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[22, 19, 17],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[22, 19, 17],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[21, 19, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[20, 19, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aléatoirement")]]), new Rule(15, new FunApp("Previous",[]),[],[[new Terminal("précédent")]]), new Rule(14, new FunApp("Previous",[]),[],[[new Terminal("précédents")]]), new Rule(13, new FunApp("Previous",[]),[],[[new Terminal("précédente")]]), new Rule(12, new FunApp("Previous",[]),[],[[new Terminal("précédentes")]]), new Rule(11, new FunApp("Previous",[]),[],[[new Terminal("précédentement")]]), new Rule(10, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédent")]]), new Rule(9, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédents")]]), new Rule(8, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédente")]]), new Rule(7, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédentes")]]), new Rule(6, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédentement")]]), new Rule(5, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédent")]]), new Rule(4, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédents")]]), new Rule(3, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédente")]]), new Rule(2, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédentes")]]), new Rule(1, new FunApp("Previous",[]),[],[[new Terminal("plus"), new Terminal("précédentement")]]), new Rule(20, new FunApp("Paste",[]),[],[[new Terminal("coller")]]), new Rule(47, new FunApp("Paste",[]),[],[[new Terminal("coller")]]), new Rule(46, new FunApp("Paste",[]),[],[[new Terminal("colle")]]), new Rule(45, new FunApp("Paste",[]),[],[[new Terminal("colles")]]), new Rule(44, new FunApp("Paste",[]),[],[[new Terminal("colle")]]), new Rule(43, new FunApp("Paste",[]),[],[[new Terminal("collons")]]), new Rule(42, new FunApp("Paste",[]),[],[[new Terminal("collez")]]), new Rule(41, new FunApp("Paste",[]),[],[[new Terminal("collent")]]), new Rule(40, new FunApp("Paste",[]),[],[[new Terminal("colle")]]), new Rule(39, new FunApp("Paste",[]),[],[[new Terminal("colles")]]), new Rule(38, new FunApp("Paste",[]),[],[[new Terminal("colle")]]), new Rule(37, new FunApp("Paste",[]),[],[[new Terminal("collions")]]), new Rule(36, new FunApp("Paste",[]),[],[[new Terminal("colliez")]]), new Rule(35, new FunApp("Paste",[]),[],[[new Terminal("collent")]]), new Rule(34, new FunApp("Paste",[]),[],[[new Terminal("colle")]]), new Rule(33, new FunApp("Paste",[]),[],[[new Terminal("collons")]]), new Rule(32, new FunApp("Paste",[]),[],[[new Terminal("collez")]]), new Rule(31, new FunApp("Paste",[]),[],[[new Terminal("collé")]]), new Rule(30, new FunApp("Paste",[]),[],[[new Terminal("collés")]]), new Rule(29, new FunApp("Paste",[]),[],[[new Terminal("collée")]]), new Rule(28, new FunApp("Paste",[]),[],[[new Terminal("collées")]]), new Rule(27, new FunApp("Paste",[]),[],[[new Terminal("collant")]]), new Rule(20, new FunApp("Parse",[]),[],[[new Terminal("analyser")]]), new Rule(47, new FunApp("Parse",[]),[],[[new Terminal("analyser")]]), new Rule(46, new FunApp("Parse",[]),[],[[new Terminal("analyse")]]), new Rule(45, new FunApp("Parse",[]),[],[[new Terminal("analyses")]]), new Rule(44, new FunApp("Parse",[]),[],[[new Terminal("analyse")]]), new Rule(43, new FunApp("Parse",[]),[],[[new Terminal("analysons")]]), new Rule(42, new FunApp("Parse",[]),[],[[new Terminal("analysez")]]), new Rule(41, new FunApp("Parse",[]),[],[[new Terminal("analysent")]]), new Rule(40, new FunApp("Parse",[]),[],[[new Terminal("analyse")]]), new Rule(39, new FunApp("Parse",[]),[],[[new Terminal("analyses")]]), new Rule(38, new FunApp("Parse",[]),[],[[new Terminal("analyse")]]), new Rule(37, new FunApp("Parse",[]),[],[[new Terminal("analysions")]]), new Rule(36, new FunApp("Parse",[]),[],[[new Terminal("analysiez")]]), new Rule(35, new FunApp("Parse",[]),[],[[new Terminal("analysent")]]), new Rule(34, new FunApp("Parse",[]),[],[[new Terminal("analyse")]]), new Rule(33, new FunApp("Parse",[]),[],[[new Terminal("analysons")]]), new Rule(32, new FunApp("Parse",[]),[],[[new Terminal("analysez")]]), new Rule(31, new FunApp("Parse",[]),[],[[new Terminal("analysé")]]), new Rule(30, new FunApp("Parse",[]),[],[[new Terminal("analysés")]]), new Rule(29, new FunApp("Parse",[]),[],[[new Terminal("analysée")]]), new Rule(28, new FunApp("Parse",[]),[],[[new Terminal("analysées")]]), new Rule(27, new FunApp("Parse",[]),[],[[new Terminal("analysant")]]), new Rule(23, new FunApp("Page",[]),[],[[new Terminal("page")]]), new Rule(87, new FunApp("Page",[]),[],[[new Terminal("pages")]]), new Rule(17, new FunApp("Norwegian",[]),[],[[new Terminal("norvégien")]]), new Rule(16, new FunApp("Norwegian",[]),[],[[new Terminal("norvégiens")]]), new Rule(17, new FunApp("Node",[]),[],[[new Terminal("noeud")]]), new Rule(16, new FunApp("Node",[]),[],[[new Terminal("noeuds")]]), new Rule(15, new FunApp("Next",[]),[],[[new Terminal("prochain")]]), new Rule(14, new FunApp("Next",[]),[],[[new Terminal("prochains")]]), new Rule(13, new FunApp("Next",[]),[],[[new Terminal("prochaine")]]), new Rule(12, new FunApp("Next",[]),[],[[new Terminal("prochaines")]]), new Rule(11, new FunApp("Next",[]),[],[[new Terminal("prochainement")]]), new Rule(10, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochain")]]), new Rule(9, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochains")]]), new Rule(8, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochaine")]]), new Rule(7, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochaines")]]), new Rule(6, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochainement")]]), new Rule(5, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochain")]]), new Rule(4, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochains")]]), new Rule(3, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochaine")]]), new Rule(2, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochaines")]]), new Rule(1, new FunApp("Next",[]),[],[[new Terminal("plus"), new Terminal("prochainement")]]), new Rule(23, new FunApp("Language",[]),[],[[new Terminal("langue")]]), new Rule(87, new FunApp("Language",[]),[],[[new Terminal("langues")]]), new Rule(18, new FunApp("Label",[new Arg(0)]),[89],[[new ArgProj(0, 0)]]), new Rule(89, new Arg(0),[23],[[new ArgProj(0, 0)]]), new Rule(89, new Arg(0),[17],[[new ArgProj(0, 0)]]), new Rule(17, new FunApp("Italian",[]),[],[[new Terminal("italien")]]), new Rule(16, new FunApp("Italian",[]),[],[[new Terminal("italiens")]]), new Rule(17, new FunApp("Integer_N",[]),[],[[new Terminal("entier")]]), new Rule(16, new FunApp("Integer_N",[]),[],[[new Terminal("entiers")]]), new Rule(85, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(84, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(83, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(82, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(81, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(80, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(79, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(78, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(77, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(76, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(75, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(74, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(73, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(72, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(71, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(70, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(69, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(68, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(67, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(66, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(65, new FunApp("IndefSgDet",[]),[],[[new Terminal("un")]]), new Rule(19, new FunApp("IndefSgDet",[]),[],[[new Terminal("un")]]), new Rule(64, new FunApp("IndefSgDet",[]),[],[[new Terminal("d'"), new Terminal("un")]]), new Rule(63, new FunApp("IndefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("un")]]), new Rule(62, new FunApp("IndefSgDet",[]),[],[[new Terminal("un")]]), new Rule(61, new FunApp("IndefSgDet",[]),[],[[new Terminal("une")]]), new Rule(24, new FunApp("IndefSgDet",[]),[],[[new Terminal("une")]]), new Rule(60, new FunApp("IndefSgDet",[]),[],[[new Terminal("d'"), new Terminal("une")]]), new Rule(59, new FunApp("IndefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("une")]]), new Rule(58, new FunApp("IndefSgDet",[]),[],[[new Terminal("une")]]), new Rule(57, new FunApp("IndefSgDet",[]),[],[[new Terminal("des")]]), new Rule(56, new FunApp("IndefSgDet",[]),[],[[new Terminal("des")]]), new Rule(55, new FunApp("IndefSgDet",[]),[],[[new Terminal("d'")]]), new Rule(55, new FunApp("IndefSgDet",[]),[],[[new Terminal("de")]]), new Rule(54, new FunApp("IndefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("des")]]), new Rule(53, new FunApp("IndefSgDet",[]),[],[[new Terminal("des")]]), new Rule(52, new FunApp("IndefSgDet",[]),[],[[new Terminal("des")]]), new Rule(51, new FunApp("IndefSgDet",[]),[],[[new Terminal("des")]]), new Rule(50, new FunApp("IndefSgDet",[]),[],[[new Terminal("d'")]]), new Rule(50, new FunApp("IndefSgDet",[]),[],[[new Terminal("de")]]), new Rule(49, new FunApp("IndefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("des")]]), new Rule(48, new FunApp("IndefSgDet",[]),[],[[new Terminal("des")]]), new Rule(85, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(84, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(83, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(82, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(81, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(80, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(79, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(78, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(77, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(76, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(75, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(74, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(73, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(72, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(71, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(70, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(69, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(68, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(67, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(66, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(65, new FunApp("IndefPlDet",[]),[],[[new Terminal("un")]]), new Rule(19, new FunApp("IndefPlDet",[]),[],[[new Terminal("un")]]), new Rule(64, new FunApp("IndefPlDet",[]),[],[[new Terminal("d'"), new Terminal("un")]]), new Rule(63, new FunApp("IndefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("un")]]), new Rule(62, new FunApp("IndefPlDet",[]),[],[[new Terminal("un")]]), new Rule(61, new FunApp("IndefPlDet",[]),[],[[new Terminal("une")]]), new Rule(24, new FunApp("IndefPlDet",[]),[],[[new Terminal("une")]]), new Rule(60, new FunApp("IndefPlDet",[]),[],[[new Terminal("d'"), new Terminal("une")]]), new Rule(59, new FunApp("IndefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("une")]]), new Rule(58, new FunApp("IndefPlDet",[]),[],[[new Terminal("une")]]), new Rule(57, new FunApp("IndefPlDet",[]),[],[[new Terminal("des")]]), new Rule(56, new FunApp("IndefPlDet",[]),[],[[new Terminal("des")]]), new Rule(55, new FunApp("IndefPlDet",[]),[],[[new Terminal("d'")]]), new Rule(55, new FunApp("IndefPlDet",[]),[],[[new Terminal("de")]]), new Rule(54, new FunApp("IndefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("des")]]), new Rule(53, new FunApp("IndefPlDet",[]),[],[[new Terminal("des")]]), new Rule(52, new FunApp("IndefPlDet",[]),[],[[new Terminal("des")]]), new Rule(51, new FunApp("IndefPlDet",[]),[],[[new Terminal("des")]]), new Rule(50, new FunApp("IndefPlDet",[]),[],[[new Terminal("d'")]]), new Rule(50, new FunApp("IndefPlDet",[]),[],[[new Terminal("de")]]), new Rule(49, new FunApp("IndefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("des")]]), new Rule(48, new FunApp("IndefPlDet",[]),[],[[new Terminal("des")]]), new Rule(17, new FunApp("German",[]),[],[[new Terminal("allemand")]]), new Rule(16, new FunApp("German",[]),[],[[new Terminal("allemands")]]), new Rule(17, new FunApp("French",[]),[],[[new Terminal("français")]]), new Rule(16, new FunApp("French",[]),[],[[new Terminal("français")]]), new Rule(17, new FunApp("Float_N",[]),[],[[new Terminal("réel")]]), new Rule(16, new FunApp("Float_N",[]),[],[[new Terminal("réels")]]), new Rule(17, new FunApp("Finnish",[]),[],[[new Terminal("finnois")]]), new Rule(16, new FunApp("Finnish",[]),[],[[new Terminal("finnois")]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[12, 87],[[new Terminal("il"), new Terminal("n'"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(1, 0), new ArgProj(0, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[12, 87],[[new Terminal("il"), new Terminal("ne"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(1, 0), new ArgProj(0, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[14, 16],[[new Terminal("il"), new Terminal("n'"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(1, 0), new ArgProj(0, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[14, 16],[[new Terminal("il"), new Terminal("ne"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(1, 0), new ArgProj(0, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[88, 87],[[new Terminal("il"), new Terminal("n'"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[88, 87],[[new Terminal("il"), new Terminal("ne"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[86, 16],[[new Terminal("il"), new Terminal("n'"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[86, 16],[[new Terminal("il"), new Terminal("ne"), new Terminal("y"), new Terminal("a"), new Terminal("pas"), new Terminal("des"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(20, new FunApp("Enter",[]),[],[[new Terminal("introduire")]]), new Rule(47, new FunApp("Enter",[]),[],[[new Terminal("introduire")]]), new Rule(46, new FunApp("Enter",[]),[],[[new Terminal("introduis")]]), new Rule(45, new FunApp("Enter",[]),[],[[new Terminal("introduis")]]), new Rule(44, new FunApp("Enter",[]),[],[[new Terminal("introduit")]]), new Rule(43, new FunApp("Enter",[]),[],[[new Terminal("introduisons")]]), new Rule(42, new FunApp("Enter",[]),[],[[new Terminal("introduisez")]]), new Rule(41, new FunApp("Enter",[]),[],[[new Terminal("introduisent")]]), new Rule(40, new FunApp("Enter",[]),[],[[new Terminal("introduise")]]), new Rule(39, new FunApp("Enter",[]),[],[[new Terminal("introduises")]]), new Rule(38, new FunApp("Enter",[]),[],[[new Terminal("introduise")]]), new Rule(37, new FunApp("Enter",[]),[],[[new Terminal("introduisions")]]), new Rule(36, new FunApp("Enter",[]),[],[[new Terminal("introduisiez")]]), new Rule(35, new FunApp("Enter",[]),[],[[new Terminal("introduisent")]]), new Rule(34, new FunApp("Enter",[]),[],[[new Terminal("introduis")]]), new Rule(33, new FunApp("Enter",[]),[],[[new Terminal("introduisons")]]), new Rule(32, new FunApp("Enter",[]),[],[[new Terminal("introduisez")]]), new Rule(31, new FunApp("Enter",[]),[],[[new Terminal("introduit")]]), new Rule(30, new FunApp("Enter",[]),[],[[new Terminal("introduits")]]), new Rule(29, new FunApp("Enter",[]),[],[[new Terminal("introduite")]]), new Rule(28, new FunApp("Enter",[]),[],[[new Terminal("introduites")]]), new Rule(27, new FunApp("Enter",[]),[],[[new Terminal("introduisant")]]), new Rule(17, new FunApp("English",[]),[],[[new Terminal("anglais")]]), new Rule(16, new FunApp("English",[]),[],[[new Terminal("anglais")]]), new Rule(20, new FunApp("Delete",[]),[],[[new Terminal("enlever")]]), new Rule(47, new FunApp("Delete",[]),[],[[new Terminal("enlever")]]), new Rule(46, new FunApp("Delete",[]),[],[[new Terminal("enleve")]]), new Rule(45, new FunApp("Delete",[]),[],[[new Terminal("enleves")]]), new Rule(44, new FunApp("Delete",[]),[],[[new Terminal("enleve")]]), new Rule(43, new FunApp("Delete",[]),[],[[new Terminal("enlevons")]]), new Rule(42, new FunApp("Delete",[]),[],[[new Terminal("enlevez")]]), new Rule(41, new FunApp("Delete",[]),[],[[new Terminal("enlevent")]]), new Rule(40, new FunApp("Delete",[]),[],[[new Terminal("enleve")]]), new Rule(39, new FunApp("Delete",[]),[],[[new Terminal("enleves")]]), new Rule(38, new FunApp("Delete",[]),[],[[new Terminal("enleve")]]), new Rule(37, new FunApp("Delete",[]),[],[[new Terminal("enlevions")]]), new Rule(36, new FunApp("Delete",[]),[],[[new Terminal("enleviez")]]), new Rule(35, new FunApp("Delete",[]),[],[[new Terminal("enlevent")]]), new Rule(34, new FunApp("Delete",[]),[],[[new Terminal("enleve")]]), new Rule(33, new FunApp("Delete",[]),[],[[new Terminal("enlevons")]]), new Rule(32, new FunApp("Delete",[]),[],[[new Terminal("enlevez")]]), new Rule(31, new FunApp("Delete",[]),[],[[new Terminal("enlevé")]]), new Rule(30, new FunApp("Delete",[]),[],[[new Terminal("enlevés")]]), new Rule(29, new FunApp("Delete",[]),[],[[new Terminal("enlevée")]]), new Rule(28, new FunApp("Delete",[]),[],[[new Terminal("enlevées")]]), new Rule(27, new FunApp("Delete",[]),[],[[new Terminal("enlevant")]]), new Rule(85, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(85, new FunApp("DefSgDet",[]),[],[[new Terminal("le")]]), new Rule(84, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(84, new FunApp("DefSgDet",[]),[],[[new Terminal("le")]]), new Rule(83, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(83, new FunApp("DefSgDet",[]),[],[[new Terminal("du")]]), new Rule(82, new FunApp("DefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(82, new FunApp("DefSgDet",[]),[],[[new Terminal("au")]]), new Rule(81, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(81, new FunApp("DefSgDet",[]),[],[[new Terminal("le")]]), new Rule(80, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(80, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(79, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(79, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(78, new FunApp("DefSgDet",[]),[],[[new Terminal("d'"), new Terminal("l'")]]), new Rule(78, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(78, new FunApp("DefSgDet",[]),[],[[new Terminal("d'"), new Terminal("la")]]), new Rule(78, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(77, new FunApp("DefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(77, new FunApp("DefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("la")]]), new Rule(76, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(76, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(75, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(74, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(73, new FunApp("DefSgDet",[]),[],[[new Terminal("des")]]), new Rule(72, new FunApp("DefSgDet",[]),[],[[new Terminal("aux")]]), new Rule(71, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(70, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(69, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(68, new FunApp("DefSgDet",[]),[],[[new Terminal("des")]]), new Rule(67, new FunApp("DefSgDet",[]),[],[[new Terminal("aux")]]), new Rule(66, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(65, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(65, new FunApp("DefSgDet",[]),[],[[new Terminal("le")]]), new Rule(19, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(19, new FunApp("DefSgDet",[]),[],[[new Terminal("le")]]), new Rule(64, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(64, new FunApp("DefSgDet",[]),[],[[new Terminal("du")]]), new Rule(63, new FunApp("DefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(63, new FunApp("DefSgDet",[]),[],[[new Terminal("au")]]), new Rule(62, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(62, new FunApp("DefSgDet",[]),[],[[new Terminal("le")]]), new Rule(61, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(61, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(24, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(24, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(60, new FunApp("DefSgDet",[]),[],[[new Terminal("d'"), new Terminal("l'")]]), new Rule(60, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(60, new FunApp("DefSgDet",[]),[],[[new Terminal("d'"), new Terminal("la")]]), new Rule(60, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(59, new FunApp("DefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(59, new FunApp("DefSgDet",[]),[],[[new Terminal("Ã"), new Terminal("la")]]), new Rule(58, new FunApp("DefSgDet",[]),[],[[new Terminal("l'")]]), new Rule(58, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(57, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(56, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(55, new FunApp("DefSgDet",[]),[],[[new Terminal("des")]]), new Rule(54, new FunApp("DefSgDet",[]),[],[[new Terminal("aux")]]), new Rule(53, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(52, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(51, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(50, new FunApp("DefSgDet",[]),[],[[new Terminal("des")]]), new Rule(49, new FunApp("DefSgDet",[]),[],[[new Terminal("aux")]]), new Rule(48, new FunApp("DefSgDet",[]),[],[[new Terminal("les")]]), new Rule(85, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(85, new FunApp("DefPlDet",[]),[],[[new Terminal("le")]]), new Rule(84, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(84, new FunApp("DefPlDet",[]),[],[[new Terminal("le")]]), new Rule(83, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(83, new FunApp("DefPlDet",[]),[],[[new Terminal("du")]]), new Rule(82, new FunApp("DefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(82, new FunApp("DefPlDet",[]),[],[[new Terminal("au")]]), new Rule(81, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(81, new FunApp("DefPlDet",[]),[],[[new Terminal("le")]]), new Rule(80, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(80, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(79, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(79, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(78, new FunApp("DefPlDet",[]),[],[[new Terminal("d'"), new Terminal("l'")]]), new Rule(78, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(78, new FunApp("DefPlDet",[]),[],[[new Terminal("d'"), new Terminal("la")]]), new Rule(78, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(77, new FunApp("DefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(77, new FunApp("DefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("la")]]), new Rule(76, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(76, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(75, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(74, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(73, new FunApp("DefPlDet",[]),[],[[new Terminal("des")]]), new Rule(72, new FunApp("DefPlDet",[]),[],[[new Terminal("aux")]]), new Rule(71, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(70, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(69, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(68, new FunApp("DefPlDet",[]),[],[[new Terminal("des")]]), new Rule(67, new FunApp("DefPlDet",[]),[],[[new Terminal("aux")]]), new Rule(66, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(65, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(65, new FunApp("DefPlDet",[]),[],[[new Terminal("le")]]), new Rule(19, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(19, new FunApp("DefPlDet",[]),[],[[new Terminal("le")]]), new Rule(64, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(64, new FunApp("DefPlDet",[]),[],[[new Terminal("du")]]), new Rule(63, new FunApp("DefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(63, new FunApp("DefPlDet",[]),[],[[new Terminal("au")]]), new Rule(62, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(62, new FunApp("DefPlDet",[]),[],[[new Terminal("le")]]), new Rule(61, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(61, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(24, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(24, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(60, new FunApp("DefPlDet",[]),[],[[new Terminal("d'"), new Terminal("l'")]]), new Rule(60, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("l'")]]), new Rule(60, new FunApp("DefPlDet",[]),[],[[new Terminal("d'"), new Terminal("la")]]), new Rule(60, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(59, new FunApp("DefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("l'")]]), new Rule(59, new FunApp("DefPlDet",[]),[],[[new Terminal("Ã"), new Terminal("la")]]), new Rule(58, new FunApp("DefPlDet",[]),[],[[new Terminal("l'")]]), new Rule(58, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(57, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(56, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(55, new FunApp("DefPlDet",[]),[],[[new Terminal("des")]]), new Rule(54, new FunApp("DefPlDet",[]),[],[[new Terminal("aux")]]), new Rule(53, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(52, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(51, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(50, new FunApp("DefPlDet",[]),[],[[new Terminal("des")]]), new Rule(49, new FunApp("DefPlDet",[]),[],[[new Terminal("aux")]]), new Rule(48, new FunApp("DefPlDet",[]),[],[[new Terminal("les")]]), new Rule(17, new FunApp("Danish",[]),[],[[new Terminal("danois")]]), new Rule(16, new FunApp("Danish",[]),[],[[new Terminal("danois")]]), new Rule(20, new FunApp("Cut",[]),[],[[new Terminal("couper")]]), new Rule(47, new FunApp("Cut",[]),[],[[new Terminal("couper")]]), new Rule(46, new FunApp("Cut",[]),[],[[new Terminal("coupe")]]), new Rule(45, new FunApp("Cut",[]),[],[[new Terminal("coupes")]]), new Rule(44, new FunApp("Cut",[]),[],[[new Terminal("coupe")]]), new Rule(43, new FunApp("Cut",[]),[],[[new Terminal("coupons")]]), new Rule(42, new FunApp("Cut",[]),[],[[new Terminal("coupez")]]), new Rule(41, new FunApp("Cut",[]),[],[[new Terminal("coupent")]]), new Rule(40, new FunApp("Cut",[]),[],[[new Terminal("coupe")]]), new Rule(39, new FunApp("Cut",[]),[],[[new Terminal("coupes")]]), new Rule(38, new FunApp("Cut",[]),[],[[new Terminal("coupe")]]), new Rule(37, new FunApp("Cut",[]),[],[[new Terminal("coupions")]]), new Rule(36, new FunApp("Cut",[]),[],[[new Terminal("coupiez")]]), new Rule(35, new FunApp("Cut",[]),[],[[new Terminal("coupent")]]), new Rule(34, new FunApp("Cut",[]),[],[[new Terminal("coupe")]]), new Rule(33, new FunApp("Cut",[]),[],[[new Terminal("coupons")]]), new Rule(32, new FunApp("Cut",[]),[],[[new Terminal("coupez")]]), new Rule(31, new FunApp("Cut",[]),[],[[new Terminal("coupé")]]), new Rule(30, new FunApp("Cut",[]),[],[[new Terminal("coupés")]]), new Rule(29, new FunApp("Cut",[]),[],[[new Terminal("coupée")]]), new Rule(28, new FunApp("Cut",[]),[],[[new Terminal("coupées")]]), new Rule(27, new FunApp("Cut",[]),[],[[new Terminal("coupant")]]), new Rule(20, new FunApp("Copy",[]),[],[[new Terminal("copier")]]), new Rule(47, new FunApp("Copy",[]),[],[[new Terminal("copier")]]), new Rule(46, new FunApp("Copy",[]),[],[[new Terminal("copie")]]), new Rule(45, new FunApp("Copy",[]),[],[[new Terminal("copies")]]), new Rule(44, new FunApp("Copy",[]),[],[[new Terminal("copie")]]), new Rule(43, new FunApp("Copy",[]),[],[[new Terminal("copions")]]), new Rule(42, new FunApp("Copy",[]),[],[[new Terminal("copiez")]]), new Rule(41, new FunApp("Copy",[]),[],[[new Terminal("copient")]]), new Rule(40, new FunApp("Copy",[]),[],[[new Terminal("copie")]]), new Rule(39, new FunApp("Copy",[]),[],[[new Terminal("copies")]]), new Rule(38, new FunApp("Copy",[]),[],[[new Terminal("copie")]]), new Rule(37, new FunApp("Copy",[]),[],[[new Terminal("copiions")]]), new Rule(36, new FunApp("Copy",[]),[],[[new Terminal("copiiez")]]), new Rule(35, new FunApp("Copy",[]),[],[[new Terminal("copient")]]), new Rule(34, new FunApp("Copy",[]),[],[[new Terminal("copie")]]), new Rule(33, new FunApp("Copy",[]),[],[[new Terminal("copions")]]), new Rule(32, new FunApp("Copy",[]),[],[[new Terminal("copiez")]]), new Rule(31, new FunApp("Copy",[]),[],[[new Terminal("copié")]]), new Rule(30, new FunApp("Copy",[]),[],[[new Terminal("copiés")]]), new Rule(29, new FunApp("Copy",[]),[],[[new Terminal("copiée")]]), new Rule(28, new FunApp("Copy",[]),[],[[new Terminal("copiées")]]), new Rule(27, new FunApp("Copy",[]),[],[[new Terminal("copiant")]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 24, 13, 23],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 24, 13, 23],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 24, 13, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 24, 13, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 19, 15, 17],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 19, 15, 17],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 19, 15, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 19, 15, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 24, 26, 23],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 24, 26, 23],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 24, 26, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 24, 26, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 19, 25, 17],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[22, 19, 25, 17],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 19, 25, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 19, 25, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[22, 24, 23],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[22, 24, 23],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[21, 24, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[20, 24, 23],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[22, 19, 17],[[new Terminal("s'"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[22, 19, 17],[[new Terminal("se"), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[21, 19, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[20, 19, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(17, new FunApp("Bulgarian",[]),[],[[new Terminal("bulgarien")]]), new Rule(16, new FunApp("Bulgarian",[]),[],[[new Terminal("bulgariens")]]), new Rule(15, new FunApp("Available",[]),[],[[new Terminal("disponible")]]), new Rule(14, new FunApp("Available",[]),[],[[new Terminal("disponibles")]]), new Rule(13, new FunApp("Available",[]),[],[[new Terminal("disponible")]]), new Rule(12, new FunApp("Available",[]),[],[[new Terminal("disponibles")]]), new Rule(11, new FunApp("Available",[]),[],[[new Terminal("disponiblement")]]), new Rule(10, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponible")]]), new Rule(9, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponibles")]]), new Rule(8, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponible")]]), new Rule(7, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponibles")]]), new Rule(6, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponiblement")]]), new Rule(5, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponible")]]), new Rule(4, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponibles")]]), new Rule(3, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponible")]]), new Rule(2, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponibles")]]), new Rule(1, new FunApp("Available",[]),[],[[new Terminal("plus"), new Terminal("disponiblement")]])],{Adjective:[25, 15, 10, 5, 86, 14, 9, 4, 26, 13, 8, 3, 88, 12, 7, 2, 11, 6, 1], Determiner:[85, 65, 75, 57, 80, 61, 70, 52, 84, 19, 74, 56, 79, 24, 69, 51, 83, 64, 73, 55, 78, 60, 68, 50, 82, 63, 72, 54, 77, 59, 67, 49, 81, 62, 71, 53, 76, 58, 66, 48], Float:[-3], Int:[-2], Noun:[89, 17, 23, 16, 87], Sentence:[18], String:[-1], Verb:[20, 21, 22, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27], _Var:[-4]})), EditorSpa: new GFConcrete({coding: "utf8"},{Available: function(cs){return new Arr(new Arr(new Suffix("disponible", Editor.concretes["EditorSpa"].rule("_0", cs)), Editor.concretes["EditorSpa"].rule("_5", cs), Editor.concretes["EditorSpa"].rule("_5", cs)), new Int(1));}, Bulgarian: function(cs){return new Arr(new Suffix("Búlgaro", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Command: function(cs){return new Arr(new Seq(Editor.concretes["EditorSpa"].rule("_12", cs), Editor.concretes["EditorSpa"].rule("_38", cs), Editor.concretes["EditorSpa"].rule("_40", cs), Editor.concretes["EditorSpa"].rule("_42", cs), Editor.concretes["EditorSpa"].rule("_55", cs)));}, CommandAdj: function(cs){return new Arr(new Seq(Editor.concretes["EditorSpa"].rule("_12", cs), Editor.concretes["EditorSpa"].rule("_14", cs).sel(Editor.concretes["EditorSpa"].rule("_24", cs).sel(Editor.concretes["EditorSpa"].rule("_63", cs))), Editor.concretes["EditorSpa"].rule("_40", cs), Editor.concretes["EditorSpa"].rule("_41", cs).sel(Editor.concretes["EditorSpa"].rule("_63", cs)),(new Arr(new Arr(Editor.concretes["EditorSpa"].rule("_13", cs), Editor.concretes["EditorSpa"].rule("_78", cs)), new Arr(Editor.concretes["EditorSpa"].rule("_78", cs), Editor.concretes["EditorSpa"].rule("_78", cs)))).sel(Editor.concretes["EditorSpa"].rule("_19", cs)).sel(Editor.concretes["EditorSpa"].rule("_21", cs))));}, Copy: function(cs){return new Arr(new Suffix("Cop", new Arr(new Str("iar"), new Str("iar"), new Str("ío"), new Str("ías"), new Str("ía"), new Str("iamos"), new Str("iáis"), new Str("ían"), new Str("íe"), new Str("íes"), new Str("íe"), new Str("iemos"), new Str("iéis"), new Str("íen"), new Str("ía"), new Str("iemos"), new Str("iad"), new Str("iado"), new Str("iados"), new Str("iada"), new Str("iadas"), new Str("iando"))), new Int(0));}, Cut: function(cs){return new Arr(new Suffix("Cort", Editor.concretes["EditorSpa"].rule("_89", cs)), new Int(0));}, Danish: function(cs){return new Arr(new Suffix("Danés", Editor.concretes["EditorSpa"].rule("_92", cs)), new Int(0));}, DefPlDet: function(cs){return Editor.concretes["EditorSpa"].rule("_109", cs);}, DefSgDet: function(cs){return Editor.concretes["EditorSpa"].rule("_109", cs);}, Delete: function(cs){return new Arr(new Suffix("Borr", Editor.concretes["EditorSpa"].rule("_89", cs)), new Int(0));}, English: function(cs){return new Arr(new Suffix("Inglés", Editor.concretes["EditorSpa"].rule("_92", cs)), new Int(0));}, Enter: function(cs){return new Arr(new Suffix("introdu", new Arr(new Str("cir"), new Str("cir"), new Str("zco"), new Str("ces"), new Str("ce"), new Str("cimos"), new Str("cís"), new Str("cen"), new Str("zca"), new Str("zcas"), new Str("zca"), new Str("zcamos"), new Str("zcáis"), new Str("zcan"), new Str("ce"), new Str("zcamos"), new Str("cid"), new Str("cido"), new Str("cidos"), new Str("cida"), new Str("cidas"), new Str("ciendo"))), new Int(0));}, ErrorMessage: function(cs){return new Arr(new Seq(new Str("no"),(new Arr(Editor.concretes["EditorSpa"].rule("_119", cs), Editor.concretes["EditorSpa"].rule("_119", cs))).sel(Editor.concretes["EditorSpa"].rule("_121", cs).sel(new Int(0))).sel(Editor.concretes["EditorSpa"].rule("_121", cs).sel(new Int(1))).sel(Editor.concretes["EditorSpa"].rule("_121", cs).sel(new Int(2))),(new Arr(Editor.concretes["EditorSpa"].rule("_128", cs), Editor.concretes["EditorSpa"].rule("_128", cs))).sel(Editor.concretes["EditorSpa"].rule("_130", cs).sel(new Int(0))).sel(Editor.concretes["EditorSpa"].rule("_130", cs).sel(new Int(1))),(new Arr(new Str("un"), new Str("una"))).sel(Editor.concretes["EditorSpa"].rule("_136", cs)),(new Arr(new Seq(Editor.concretes["EditorSpa"].rule("_139", cs), Editor.concretes["EditorSpa"].rule("_140", cs)), new Seq(Editor.concretes["EditorSpa"].rule("_140", cs), Editor.concretes["EditorSpa"].rule("_139", cs)))).sel(Editor.concretes["EditorSpa"].rule("_29", cs))));}, Finnish: function(cs){return new Arr(new Suffix("Finlandés", Editor.concretes["EditorSpa"].rule("_92", cs)), new Int(0));}, Float_N: function(cs){return new Arr(new Arr(new Seq(new Str("número"), new Str("real")), new Seq(new Str("números"), new Str("real"))), new Int(0));}, French: function(cs){return new Arr(new Suffix("Francés", Editor.concretes["EditorSpa"].rule("_92", cs)), new Int(0));}, German: function(cs){return new Arr(new Suffix("Alemán", Editor.concretes["EditorSpa"].rule("_92", cs)), new Int(0));}, IndefPlDet: function(cs){return Editor.concretes["EditorSpa"].rule("_176", cs);}, IndefSgDet: function(cs){return Editor.concretes["EditorSpa"].rule("_176", cs);}, Integer_N: function(cs){return new Arr(new Arr(new Seq(new Str("número"), new Str("entero")), new Seq(new Str("números"), new Str("entero"))), new Int(0));}, Italian: function(cs){return new Arr(new Suffix("Italiano", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Label: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_12", cs));}, Language: function(cs){return new Arr(new Suffix("lenguaje", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Next: function(cs){return new Arr(new Arr(new Suffix("siguiente", Editor.concretes["EditorSpa"].rule("_0", cs)), Editor.concretes["EditorSpa"].rule("_190", cs), Editor.concretes["EditorSpa"].rule("_190", cs)), new Int(1));}, Node: function(cs){return new Arr(new Suffix("nodo", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Norwegian: function(cs){return new Arr(new Suffix("Noruego", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Page: function(cs){return new Arr(new Suffix("página", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(1));}, Parse: function(cs){return new Arr(new Arr(new Str("Analizar"), new Str("Analizar"), new Str("Analizo"), new Str("Analizas"), new Str("Analiza"), new Str("Analizamos"), new Str("Analizáis"), new Str("Analizan"), new Str("Analice"), new Str("Analices"), new Str("Analice"), new Str("Analicemos"), new Str("Analicéis"), new Str("Analicen"), new Str("Analiza"), new Str("Analicemos"), new Str("Analizad"), new Str("sintácticamente"), new Str("sintácticamentos"), new Str("sintácticamenta"), new Str("sintácticamentas"), new Str("Analizando")), new Int(0));}, Paste: function(cs){return new Arr(new Suffix("Peg", new Arr(new Str("ar"), new Str("ar"), new Str("o"), new Str("as"), new Str("a"), new Str("amos"), new Str("áis"), new Str("an"), new Str("ue"), new Str("ues"), new Str("ue"), new Str("uemos"), new Str("uéis"), new Str("uen"), new Str("a"), new Str("uemos"), new Str("ad"), new Str("ado"), new Str("ados"), new Str("ada"), new Str("adas"), new Str("ando"))), new Int(0));}, Previous: function(cs){return new Arr(new Arr(new Suffix("anterior", new Arr(new Str(""), new Str("es"), new Str(""), new Str("es"), new Str("mente"))), Editor.concretes["EditorSpa"].rule("_209", cs), Editor.concretes["EditorSpa"].rule("_209", cs)), new Int(1));}, RandomlyCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorSpa"].rule("_12", cs), Editor.concretes["EditorSpa"].rule("_38", cs), Editor.concretes["EditorSpa"].rule("_40", cs), Editor.concretes["EditorSpa"].rule("_42", cs), Editor.concretes["EditorSpa"].rule("_55", cs), new Str("aleatoriamente")));}, Redo: function(cs){return new Arr(new Suffix("reh", Editor.concretes["EditorSpa"].rule("_214", cs)), new Int(0));}, Refine: function(cs){return new Arr(new Suffix("Refin", Editor.concretes["EditorSpa"].rule("_89", cs)), new Int(0));}, Refinement: function(cs){return new Arr(new Suffix("refinamiento", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Replace: function(cs){return new Arr(new Suffix("Reempla", new Arr(new Str("zar"), new Str("zar"), new Str("zo"), new Str("zas"), new Str("za"), new Str("zamos"), new Str("záis"), new Str("zan"), new Str("ce"), new Str("ces"), new Str("ce"), new Str("cemos"), new Str("céis"), new Str("cen"), new Str("za"), new Str("cemos"), new Str("zad"), new Str("zado"), new Str("zados"), new Str("zada"), new Str("zadas"), new Str("zando"))), new Int(0));}, Russian: function(cs){return new Arr(new Suffix("Ruso", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Select: function(cs){return new Arr(new Suffix("Seleccion", Editor.concretes["EditorSpa"].rule("_89", cs)), new Int(0));}, Show: function(cs){return new Arr(new Suffix("Mostr", Editor.concretes["EditorSpa"].rule("_89", cs)), new Int(0));}, SingleWordCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorSpa"].rule("_12", cs), Editor.concretes["EditorSpa"].rule("_14", cs).sel((new Arr(new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(1))).sel(Editor.concretes["EditorSpa"].rule("_31", cs))), Editor.concretes["EditorSpa"].rule("_41", cs).sel(Editor.concretes["EditorSpa"].rule("_31", cs))));}, Spanish: function(cs){return new Arr(new Suffix("Español", Editor.concretes["EditorSpa"].rule("_92", cs)), new Int(0));}, String_N: function(cs){return new Arr(new Arr(new Seq(new Str("cadena"), new Str("de"), new Str("caracteres")), new Seq(new Str("cadenas"), new Str("de"), new Str("caracteres"))), new Int(1));}, Swedish: function(cs){return new Arr(new Suffix("Sueco", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(0));}, Tree: function(cs){return new Arr(new Suffix("árbol", Editor.concretes["EditorSpa"].rule("_92", cs)), new Int(0));}, Undo: function(cs){return new Arr(new Suffix("desh", Editor.concretes["EditorSpa"].rule("_214", cs)), new Int(0));}, Wrap: function(cs){return new Arr(new Suffix("env", new Arr(new Str("olver"), new Str("olver"), new Str("uelvo"), new Str("uelves"), new Str("uelve"), new Str("olvemos"), new Str("olvéis"), new Str("uelven"), new Str("uelva"), new Str("uelvas"), new Str("uelva"), new Str("olvamos"), new Str("olváis"), new Str("uelvan"), new Str("uelve"), new Str("olvamos"), new Str("olved"), new Str("olvido"), new Str("olvidos"), new Str("olvida"), new Str("olvidas"), new Str("olviendo"))), new Int(0));}, Wrapper: function(cs){return new Arr(new Suffix("envoltura", Editor.concretes["EditorSpa"].rule("_8", cs)), new Int(1));}, _0: function(cs){return new Arr(new Str(""), new Str("s"), new Str(""), new Str("s"), new Str("mente"));}, _100: function(cs){return new Seq(new Str("de"), new Str("los"));}, _101: function(cs){return new Seq(new Str("a"), new Str("los"));}, _102: function(cs){return new Arr(new Str("los"), new Str("los"), Editor.concretes["EditorSpa"].rule("_100", cs), Editor.concretes["EditorSpa"].rule("_101", cs));}, _103: function(cs){return new Seq(new Str("de"), new Str("las"));}, _104: function(cs){return new Seq(new Str("a"), new Str("las"));}, _105: function(cs){return new Arr(new Str("las"), new Str("las"), Editor.concretes["EditorSpa"].rule("_103", cs), Editor.concretes["EditorSpa"].rule("_104", cs));}, _106: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_102", cs), Editor.concretes["EditorSpa"].rule("_105", cs));}, _107: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_99", cs), Editor.concretes["EditorSpa"].rule("_106", cs));}, _108: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_107", cs), Editor.concretes["EditorSpa"].rule("_107", cs));}, _109: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_108", cs));}, _11: function(cs){return cs[0].sel(new Int(0));}, _117: function(cs){return new Arr(new Str("he"), new Str("has"), new Str("hay"));}, _118: function(cs){return new Arr(new Str("hemos"), new Str("habéis"), new Str("han"));}, _119: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_117", cs), Editor.concretes["EditorSpa"].rule("_118", cs));}, _12: function(cs){return Editor.concretes["EditorSpa"].rule("_11", cs).sel(new Int(0));}, _121: function(cs){return new Arr(new Int(0), new Int(0), new Int(2));}, _128: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_13", cs), Editor.concretes["EditorSpa"].rule("_13", cs));}, _13: function(cs){return new Seq();}, _130: function(cs){return new Arr(new Int(0), new Int(0));}, _136: function(cs){return cs[1].sel(new Int(1));}, _138: function(cs){return Editor.concretes["EditorSpa"].rule("_69", cs).sel(Editor.concretes["EditorSpa"].rule("_136", cs));}, _139: function(cs){return Editor.concretes["EditorSpa"].rule("_12", cs).sel(Editor.concretes["EditorSpa"].rule("_138", cs));}, _14: function(cs){return new Arr(new Str("&+"), Editor.concretes["EditorSpa"].rule("_13", cs));}, _140: function(cs){return Editor.concretes["EditorSpa"].rule("_43", cs).sel(new Int(0));}, _15: function(cs){return new Arr(new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(1), new Int(1));}, _157: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_13", cs), Editor.concretes["EditorSpa"].rule("_13", cs), Editor.concretes["EditorSpa"].rule("_13", cs), Editor.concretes["EditorSpa"].rule("_13", cs));}, _158: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_157", cs), Editor.concretes["EditorSpa"].rule("_157", cs));}, _159: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_158", cs), Editor.concretes["EditorSpa"].rule("_158", cs));}, _16: function(cs){return new Arr(new Int(13), new Int(13));}, _160: function(cs){return new Seq(new Str("de"), new Str("un"));}, _161: function(cs){return new Seq(new Str("a"), new Str("un"));}, _162: function(cs){return new Arr(new Str("un"), new Str("un"), Editor.concretes["EditorSpa"].rule("_160", cs), Editor.concretes["EditorSpa"].rule("_161", cs));}, _163: function(cs){return new Seq(new Str("de"), new Str("una"));}, _164: function(cs){return new Seq(new Str("a"), new Str("una"));}, _165: function(cs){return new Arr(new Str("una"), new Str("una"), Editor.concretes["EditorSpa"].rule("_163", cs), Editor.concretes["EditorSpa"].rule("_164", cs));}, _166: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_162", cs), Editor.concretes["EditorSpa"].rule("_165", cs));}, _167: function(cs){return new Seq(new Str("de"), new Str("unos"));}, _168: function(cs){return new Seq(new Str("a"), new Str("unos"));}, _169: function(cs){return new Arr(new Str("unos"), new Str("unos"), Editor.concretes["EditorSpa"].rule("_167", cs), Editor.concretes["EditorSpa"].rule("_168", cs));}, _17: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_16", cs), Editor.concretes["EditorSpa"].rule("_16", cs));}, _170: function(cs){return new Seq(new Str("de"), new Str("unas"));}, _171: function(cs){return new Seq(new Str("a"), new Str("unas"));}, _172: function(cs){return new Arr(new Str("unas"), new Str("unas"), Editor.concretes["EditorSpa"].rule("_170", cs), Editor.concretes["EditorSpa"].rule("_171", cs));}, _173: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_169", cs), Editor.concretes["EditorSpa"].rule("_172", cs));}, _174: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_166", cs), Editor.concretes["EditorSpa"].rule("_173", cs));}, _175: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_159", cs), Editor.concretes["EditorSpa"].rule("_174", cs));}, _176: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_175", cs));}, _18: function(cs){return new Arr(new Int(1), new Int(0));}, _187: function(cs){return new Seq(new Str("más"), new Str("siguiente"));}, _188: function(cs){return new Seq(new Str("más"), new Str("siguientes"));}, _189: function(cs){return new Seq(new Str("más"), new Str("siguientemente"));}, _19: function(cs){return Editor.concretes["EditorSpa"].rule("_18", cs).sel(new Int(0));}, _190: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_187", cs), Editor.concretes["EditorSpa"].rule("_188", cs), Editor.concretes["EditorSpa"].rule("_187", cs), Editor.concretes["EditorSpa"].rule("_188", cs), Editor.concretes["EditorSpa"].rule("_189", cs));}, _2: function(cs){return new Seq(new Str("más"), new Str("disponible"));}, _20: function(cs){return Editor.concretes["EditorSpa"].rule("_17", cs).sel(Editor.concretes["EditorSpa"].rule("_19", cs));}, _206: function(cs){return new Seq(new Str("más"), new Str("anterior"));}, _207: function(cs){return new Seq(new Str("más"), new Str("anteriores"));}, _208: function(cs){return new Seq(new Str("más"), new Str("anteriormente"));}, _209: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_206", cs), Editor.concretes["EditorSpa"].rule("_207", cs), Editor.concretes["EditorSpa"].rule("_206", cs), Editor.concretes["EditorSpa"].rule("_207", cs), Editor.concretes["EditorSpa"].rule("_208", cs));}, _21: function(cs){return Editor.concretes["EditorSpa"].rule("_18", cs).sel(new Int(1));}, _214: function(cs){return new Arr(new Str("acer"), new Str("acer"), new Str("ago"), new Str("aces"), new Str("ace"), new Str("acemos"), new Str("acéis"), new Str("acen"), new Str("aga"), new Str("agas"), new Str("aga"), new Str("agamos"), new Str("agáis"), new Str("agan"), new Str("az"), new Str("agamos"), new Str("aced"), new Str("echo"), new Str("echos"), new Str("echa"), new Str("echas"), new Str("aciendo"));}, _22: function(cs){return Editor.concretes["EditorSpa"].rule("_20", cs).sel(Editor.concretes["EditorSpa"].rule("_21", cs));}, _23: function(cs){return Editor.concretes["EditorSpa"].rule("_15", cs).sel(Editor.concretes["EditorSpa"].rule("_22", cs));}, _24: function(cs){return new Arr(new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), new Int(0), Editor.concretes["EditorSpa"].rule("_23", cs));}, _25: function(cs){return new Arr(new Int(2), new Int(8));}, _253: function(cs){return new Arr(cs[0], cs[0], cs[0], cs[0], cs[0]);}, _256: function(cs){return new Arr(cs[0], cs[0], cs[0], cs[0]);}, _257: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_256", cs), Editor.concretes["EditorSpa"].rule("_256", cs));}, _258: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_257", cs), Editor.concretes["EditorSpa"].rule("_257", cs));}, _26: function(cs){return cs[2].sel(new Int(1));}, _27: function(cs){return Editor.concretes["EditorSpa"].rule("_25", cs).sel(Editor.concretes["EditorSpa"].rule("_26", cs));}, _28: function(cs){return new Arr(new Int(12), new Int(13));}, _29: function(cs){return cs[0].sel(new Int(1));}, _3: function(cs){return new Seq(new Str("más"), new Str("disponibles"));}, _30: function(cs){return Editor.concretes["EditorSpa"].rule("_18", cs).sel(Editor.concretes["EditorSpa"].rule("_29", cs));}, _31: function(cs){return Editor.concretes["EditorSpa"].rule("_28", cs).sel(Editor.concretes["EditorSpa"].rule("_30", cs));}, _32: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_27", cs), Editor.concretes["EditorSpa"].rule("_31", cs));}, _33: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_31", cs), Editor.concretes["EditorSpa"].rule("_31", cs));}, _34: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_32", cs), Editor.concretes["EditorSpa"].rule("_33", cs));}, _35: function(cs){return Editor.concretes["EditorSpa"].rule("_34", cs).sel(Editor.concretes["EditorSpa"].rule("_19", cs));}, _36: function(cs){return Editor.concretes["EditorSpa"].rule("_35", cs).sel(Editor.concretes["EditorSpa"].rule("_21", cs));}, _37: function(cs){return Editor.concretes["EditorSpa"].rule("_24", cs).sel(Editor.concretes["EditorSpa"].rule("_36", cs));}, _38: function(cs){return Editor.concretes["EditorSpa"].rule("_14", cs).sel(Editor.concretes["EditorSpa"].rule("_37", cs));}, _39: function(cs){return new Arr(new Str("me"), new Str("te"), new Str("le"), new Str("nos"), new Str("vos"), new Str("les"), new Str("me"), new Str("te"), new Str("le"), new Str("nos"), new Str("vos"), new Str("les"), Editor.concretes["EditorSpa"].rule("_13", cs), Editor.concretes["EditorSpa"].rule("_13", cs));}, _4: function(cs){return new Seq(new Str("más"), new Str("disponiblemente"));}, _40: function(cs){return Editor.concretes["EditorSpa"].rule("_39", cs).sel(Editor.concretes["EditorSpa"].rule("_22", cs));}, _41: function(cs){return new Arr(new Str("me"), new Str("te"), new Str("lo"), new Str("nos"), new Str("vos"), new Str("los"), new Str("me"), new Str("te"), new Str("la"), new Str("nos"), new Str("vos"), new Str("las"), new Str("se"), Editor.concretes["EditorSpa"].rule("_13", cs));}, _42: function(cs){return Editor.concretes["EditorSpa"].rule("_41", cs).sel(Editor.concretes["EditorSpa"].rule("_36", cs));}, _43: function(cs){return cs[1].sel(new Int(0));}, _44: function(cs){return Editor.concretes["EditorSpa"].rule("_43", cs).sel(new Int(1));}, _45: function(cs){return Editor.concretes["EditorSpa"].rule("_44", cs).sel(new Int(0));}, _46: function(cs){return Editor.concretes["EditorSpa"].rule("_45", cs).sel(Editor.concretes["EditorSpa"].rule("_26", cs));}, _47: function(cs){return Editor.concretes["EditorSpa"].rule("_46", cs).sel(new Int(1));}, _48: function(cs){return cs[2].sel(new Int(0));}, _49: function(cs){return Editor.concretes["EditorSpa"].rule("_48", cs).sel(new Int(0));}, _5: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_2", cs), Editor.concretes["EditorSpa"].rule("_3", cs), Editor.concretes["EditorSpa"].rule("_2", cs), Editor.concretes["EditorSpa"].rule("_3", cs), Editor.concretes["EditorSpa"].rule("_4", cs));}, _50: function(cs){return new Seq(Editor.concretes["EditorSpa"].rule("_47", cs), Editor.concretes["EditorSpa"].rule("_49", cs));}, _51: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_13", cs), Editor.concretes["EditorSpa"].rule("_50", cs));}, _52: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_50", cs), Editor.concretes["EditorSpa"].rule("_50", cs));}, _53: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_51", cs), Editor.concretes["EditorSpa"].rule("_52", cs));}, _54: function(cs){return Editor.concretes["EditorSpa"].rule("_53", cs).sel(Editor.concretes["EditorSpa"].rule("_19", cs));}, _55: function(cs){return Editor.concretes["EditorSpa"].rule("_54", cs).sel(Editor.concretes["EditorSpa"].rule("_21", cs));}, _58: function(cs){return cs[3].sel(new Int(1));}, _59: function(cs){return Editor.concretes["EditorSpa"].rule("_25", cs).sel(Editor.concretes["EditorSpa"].rule("_58", cs));}, _60: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_59", cs), Editor.concretes["EditorSpa"].rule("_31", cs));}, _61: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_60", cs), Editor.concretes["EditorSpa"].rule("_33", cs));}, _62: function(cs){return Editor.concretes["EditorSpa"].rule("_61", cs).sel(Editor.concretes["EditorSpa"].rule("_19", cs));}, _63: function(cs){return Editor.concretes["EditorSpa"].rule("_62", cs).sel(Editor.concretes["EditorSpa"].rule("_21", cs));}, _67: function(cs){return Editor.concretes["EditorSpa"].rule("_45", cs).sel(Editor.concretes["EditorSpa"].rule("_58", cs));}, _68: function(cs){return Editor.concretes["EditorSpa"].rule("_67", cs).sel(new Int(1));}, _69: function(cs){return new Arr(new Int(0), new Int(2));}, _70: function(cs){return Editor.concretes["EditorSpa"].rule("_69", cs).sel(Editor.concretes["EditorSpa"].rule("_58", cs));}, _71: function(cs){return Editor.concretes["EditorSpa"].rule("_49", cs).sel(Editor.concretes["EditorSpa"].rule("_70", cs));}, _72: function(cs){return cs[3].sel(new Int(0));}, _73: function(cs){return Editor.concretes["EditorSpa"].rule("_72", cs).sel(new Int(0));}, _74: function(cs){return new Seq(Editor.concretes["EditorSpa"].rule("_71", cs), Editor.concretes["EditorSpa"].rule("_73", cs));}, _75: function(cs){return new Seq(Editor.concretes["EditorSpa"].rule("_73", cs), Editor.concretes["EditorSpa"].rule("_71", cs));}, _76: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_74", cs), Editor.concretes["EditorSpa"].rule("_75", cs));}, _77: function(cs){return Editor.concretes["EditorSpa"].rule("_76", cs).sel(Editor.concretes["EditorSpa"].rule("_26", cs));}, _78: function(cs){return new Seq(Editor.concretes["EditorSpa"].rule("_68", cs), Editor.concretes["EditorSpa"].rule("_77", cs));}, _8: function(cs){return new Arr(new Str(""), new Str("s"));}, _89: function(cs){return new Arr(new Str("ar"), new Str("ar"), new Str("o"), new Str("as"), new Str("a"), new Str("amos"), new Str("áis"), new Str("an"), new Str("e"), new Str("es"), new Str("e"), new Str("emos"), new Str("éis"), new Str("en"), new Str("a"), new Str("emos"), new Str("ad"), new Str("ado"), new Str("ados"), new Str("ada"), new Str("adas"), new Str("ando"));}, _92: function(cs){return new Arr(new Str(""), new Str("es"));}, _95: function(cs){return new Arr(new Str("el"), new Str("el"), new Str("del"), new Str("al"));}, _96: function(cs){return new Seq(new Str("de"), new Str("la"));}, _97: function(cs){return new Seq(new Str("a"), new Str("la"));}, _98: function(cs){return new Arr(new Str("la"), new Str("la"), Editor.concretes["EditorSpa"].rule("_96", cs), Editor.concretes["EditorSpa"].rule("_97", cs));}, _99: function(cs){return new Arr(Editor.concretes["EditorSpa"].rule("_95", cs), Editor.concretes["EditorSpa"].rule("_98", cs));}, Adjective: function(cs){return new Arr(new Arr(Editor.concretes["EditorSpa"].rule("_253", cs), Editor.concretes["EditorSpa"].rule("_253", cs), Editor.concretes["EditorSpa"].rule("_253", cs)), new Int(0));}, Determiner: function(cs){return new Arr(new Arr(Editor.concretes["EditorSpa"].rule("_258", cs), Editor.concretes["EditorSpa"].rule("_258", cs)));}, Noun: function(cs){return new Arr(new Arr(cs[0], cs[0]), new Int(0));}, Sentence: function(cs){return new Arr(cs[0]);}, Verb: function(cs){return new Arr(new Arr(cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0]), new Int(0));}, "Int": function(cs){return new Arr(cs[0]);}, "Float": function(cs){return new Arr(cs[0]);}, "String": function(cs){return new Arr(cs[0]);}}, new Parser("Sentence",[new Rule(22, new FunApp("Wrapper",[]),[],[[new Terminal("envoltura")]]), new Rule(78, new FunApp("Wrapper",[]),[],[[new Terminal("envolturas")]]), new Rule(20, new FunApp("Wrap",[]),[],[[new Terminal("envolver")]]), new Rule(46, new FunApp("Wrap",[]),[],[[new Terminal("envolver")]]), new Rule(45, new FunApp("Wrap",[]),[],[[new Terminal("envuelvo")]]), new Rule(44, new FunApp("Wrap",[]),[],[[new Terminal("envuelves")]]), new Rule(43, new FunApp("Wrap",[]),[],[[new Terminal("envuelve")]]), new Rule(42, new FunApp("Wrap",[]),[],[[new Terminal("envolvemos")]]), new Rule(41, new FunApp("Wrap",[]),[],[[new Terminal("envolvéis")]]), new Rule(40, new FunApp("Wrap",[]),[],[[new Terminal("envuelven")]]), new Rule(39, new FunApp("Wrap",[]),[],[[new Terminal("envuelva")]]), new Rule(38, new FunApp("Wrap",[]),[],[[new Terminal("envuelvas")]]), new Rule(37, new FunApp("Wrap",[]),[],[[new Terminal("envuelva")]]), new Rule(36, new FunApp("Wrap",[]),[],[[new Terminal("envolvamos")]]), new Rule(35, new FunApp("Wrap",[]),[],[[new Terminal("envolváis")]]), new Rule(34, new FunApp("Wrap",[]),[],[[new Terminal("envuelvan")]]), new Rule(33, new FunApp("Wrap",[]),[],[[new Terminal("envuelve")]]), new Rule(32, new FunApp("Wrap",[]),[],[[new Terminal("envolvamos")]]), new Rule(31, new FunApp("Wrap",[]),[],[[new Terminal("envolved")]]), new Rule(30, new FunApp("Wrap",[]),[],[[new Terminal("envolvido")]]), new Rule(29, new FunApp("Wrap",[]),[],[[new Terminal("envolvidos")]]), new Rule(28, new FunApp("Wrap",[]),[],[[new Terminal("envolvida")]]), new Rule(27, new FunApp("Wrap",[]),[],[[new Terminal("envolvidas")]]), new Rule(26, new FunApp("Wrap",[]),[],[[new Terminal("envolviendo")]]), new Rule(20, new FunApp("Undo",[]),[],[[new Terminal("deshacer")]]), new Rule(46, new FunApp("Undo",[]),[],[[new Terminal("deshacer")]]), new Rule(45, new FunApp("Undo",[]),[],[[new Terminal("deshago")]]), new Rule(44, new FunApp("Undo",[]),[],[[new Terminal("deshaces")]]), new Rule(43, new FunApp("Undo",[]),[],[[new Terminal("deshace")]]), new Rule(42, new FunApp("Undo",[]),[],[[new Terminal("deshacemos")]]), new Rule(41, new FunApp("Undo",[]),[],[[new Terminal("deshacéis")]]), new Rule(40, new FunApp("Undo",[]),[],[[new Terminal("deshacen")]]), new Rule(39, new FunApp("Undo",[]),[],[[new Terminal("deshaga")]]), new Rule(38, new FunApp("Undo",[]),[],[[new Terminal("deshagas")]]), new Rule(37, new FunApp("Undo",[]),[],[[new Terminal("deshaga")]]), new Rule(36, new FunApp("Undo",[]),[],[[new Terminal("deshagamos")]]), new Rule(35, new FunApp("Undo",[]),[],[[new Terminal("deshagáis")]]), new Rule(34, new FunApp("Undo",[]),[],[[new Terminal("deshagan")]]), new Rule(33, new FunApp("Undo",[]),[],[[new Terminal("deshaz")]]), new Rule(32, new FunApp("Undo",[]),[],[[new Terminal("deshagamos")]]), new Rule(31, new FunApp("Undo",[]),[],[[new Terminal("deshaced")]]), new Rule(30, new FunApp("Undo",[]),[],[[new Terminal("deshecho")]]), new Rule(29, new FunApp("Undo",[]),[],[[new Terminal("deshechos")]]), new Rule(28, new FunApp("Undo",[]),[],[[new Terminal("deshecha")]]), new Rule(27, new FunApp("Undo",[]),[],[[new Terminal("deshechas")]]), new Rule(26, new FunApp("Undo",[]),[],[[new Terminal("deshaciendo")]]), new Rule(17, new FunApp("Tree",[]),[],[[new Terminal("árbol")]]), new Rule(16, new FunApp("Tree",[]),[],[[new Terminal("árboles")]]), new Rule(17, new FunApp("Swedish",[]),[],[[new Terminal("Sueco")]]), new Rule(16, new FunApp("Swedish",[]),[],[[new Terminal("Suecos")]]), new Rule(22, new FunApp("String_N",[]),[],[[new Terminal("cadena"), new Terminal("de"), new Terminal("caracteres")]]), new Rule(78, new FunApp("String_N",[]),[],[[new Terminal("cadenas"), new Terminal("de"), new Terminal("caracteres")]]), new Rule(17, new FunApp("Spanish",[]),[],[[new Terminal("Español")]]), new Rule(16, new FunApp("Spanish",[]),[],[[new Terminal("Españoles")]]), new Rule(18, new FunApp("SingleWordCommand",[new Arg(0)]),[21],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se")]]), new Rule(18, new FunApp("SingleWordCommand",[new Arg(0)]),[20],[[new ArgProj(0, 0)]]), new Rule(20, new FunApp("Show",[]),[],[[new Terminal("Mostrar")]]), new Rule(46, new FunApp("Show",[]),[],[[new Terminal("Mostrar")]]), new Rule(45, new FunApp("Show",[]),[],[[new Terminal("Mostro")]]), new Rule(44, new FunApp("Show",[]),[],[[new Terminal("Mostras")]]), new Rule(43, new FunApp("Show",[]),[],[[new Terminal("Mostra")]]), new Rule(42, new FunApp("Show",[]),[],[[new Terminal("Mostramos")]]), new Rule(41, new FunApp("Show",[]),[],[[new Terminal("Mostráis")]]), new Rule(40, new FunApp("Show",[]),[],[[new Terminal("Mostran")]]), new Rule(39, new FunApp("Show",[]),[],[[new Terminal("Mostre")]]), new Rule(38, new FunApp("Show",[]),[],[[new Terminal("Mostres")]]), new Rule(37, new FunApp("Show",[]),[],[[new Terminal("Mostre")]]), new Rule(36, new FunApp("Show",[]),[],[[new Terminal("Mostremos")]]), new Rule(35, new FunApp("Show",[]),[],[[new Terminal("Mostréis")]]), new Rule(34, new FunApp("Show",[]),[],[[new Terminal("Mostren")]]), new Rule(33, new FunApp("Show",[]),[],[[new Terminal("Mostra")]]), new Rule(32, new FunApp("Show",[]),[],[[new Terminal("Mostremos")]]), new Rule(31, new FunApp("Show",[]),[],[[new Terminal("Mostrad")]]), new Rule(30, new FunApp("Show",[]),[],[[new Terminal("Mostrado")]]), new Rule(29, new FunApp("Show",[]),[],[[new Terminal("Mostrados")]]), new Rule(28, new FunApp("Show",[]),[],[[new Terminal("Mostrada")]]), new Rule(27, new FunApp("Show",[]),[],[[new Terminal("Mostradas")]]), new Rule(26, new FunApp("Show",[]),[],[[new Terminal("Mostrando")]]), new Rule(20, new FunApp("Select",[]),[],[[new Terminal("Seleccionar")]]), new Rule(46, new FunApp("Select",[]),[],[[new Terminal("Seleccionar")]]), new Rule(45, new FunApp("Select",[]),[],[[new Terminal("Selecciono")]]), new Rule(44, new FunApp("Select",[]),[],[[new Terminal("Seleccionas")]]), new Rule(43, new FunApp("Select",[]),[],[[new Terminal("Selecciona")]]), new Rule(42, new FunApp("Select",[]),[],[[new Terminal("Seleccionamos")]]), new Rule(41, new FunApp("Select",[]),[],[[new Terminal("Seleccionáis")]]), new Rule(40, new FunApp("Select",[]),[],[[new Terminal("Seleccionan")]]), new Rule(39, new FunApp("Select",[]),[],[[new Terminal("Seleccione")]]), new Rule(38, new FunApp("Select",[]),[],[[new Terminal("Selecciones")]]), new Rule(37, new FunApp("Select",[]),[],[[new Terminal("Seleccione")]]), new Rule(36, new FunApp("Select",[]),[],[[new Terminal("Seleccionemos")]]), new Rule(35, new FunApp("Select",[]),[],[[new Terminal("Seleccionéis")]]), new Rule(34, new FunApp("Select",[]),[],[[new Terminal("Seleccionen")]]), new Rule(33, new FunApp("Select",[]),[],[[new Terminal("Selecciona")]]), new Rule(32, new FunApp("Select",[]),[],[[new Terminal("Seleccionemos")]]), new Rule(31, new FunApp("Select",[]),[],[[new Terminal("Seleccionad")]]), new Rule(30, new FunApp("Select",[]),[],[[new Terminal("Seleccionado")]]), new Rule(29, new FunApp("Select",[]),[],[[new Terminal("Seleccionados")]]), new Rule(28, new FunApp("Select",[]),[],[[new Terminal("Seleccionada")]]), new Rule(27, new FunApp("Select",[]),[],[[new Terminal("Seleccionadas")]]), new Rule(26, new FunApp("Select",[]),[],[[new Terminal("Seleccionando")]]), new Rule(17, new FunApp("Russian",[]),[],[[new Terminal("Ruso")]]), new Rule(16, new FunApp("Russian",[]),[],[[new Terminal("Rusos")]]), new Rule(20, new FunApp("Replace",[]),[],[[new Terminal("Reemplazar")]]), new Rule(46, new FunApp("Replace",[]),[],[[new Terminal("Reemplazar")]]), new Rule(45, new FunApp("Replace",[]),[],[[new Terminal("Reemplazo")]]), new Rule(44, new FunApp("Replace",[]),[],[[new Terminal("Reemplazas")]]), new Rule(43, new FunApp("Replace",[]),[],[[new Terminal("Reemplaza")]]), new Rule(42, new FunApp("Replace",[]),[],[[new Terminal("Reemplazamos")]]), new Rule(41, new FunApp("Replace",[]),[],[[new Terminal("Reemplazáis")]]), new Rule(40, new FunApp("Replace",[]),[],[[new Terminal("Reemplazan")]]), new Rule(39, new FunApp("Replace",[]),[],[[new Terminal("Reemplace")]]), new Rule(38, new FunApp("Replace",[]),[],[[new Terminal("Reemplaces")]]), new Rule(37, new FunApp("Replace",[]),[],[[new Terminal("Reemplace")]]), new Rule(36, new FunApp("Replace",[]),[],[[new Terminal("Reemplacemos")]]), new Rule(35, new FunApp("Replace",[]),[],[[new Terminal("Reemplacéis")]]), new Rule(34, new FunApp("Replace",[]),[],[[new Terminal("Reemplacen")]]), new Rule(33, new FunApp("Replace",[]),[],[[new Terminal("Reemplaza")]]), new Rule(32, new FunApp("Replace",[]),[],[[new Terminal("Reemplacemos")]]), new Rule(31, new FunApp("Replace",[]),[],[[new Terminal("Reemplazad")]]), new Rule(30, new FunApp("Replace",[]),[],[[new Terminal("Reemplazado")]]), new Rule(29, new FunApp("Replace",[]),[],[[new Terminal("Reemplazados")]]), new Rule(28, new FunApp("Replace",[]),[],[[new Terminal("Reemplazada")]]), new Rule(27, new FunApp("Replace",[]),[],[[new Terminal("Reemplazadas")]]), new Rule(26, new FunApp("Replace",[]),[],[[new Terminal("Reemplazando")]]), new Rule(17, new FunApp("Refinement",[]),[],[[new Terminal("refinamiento")]]), new Rule(16, new FunApp("Refinement",[]),[],[[new Terminal("refinamientos")]]), new Rule(20, new FunApp("Refine",[]),[],[[new Terminal("Refinar")]]), new Rule(46, new FunApp("Refine",[]),[],[[new Terminal("Refinar")]]), new Rule(45, new FunApp("Refine",[]),[],[[new Terminal("Refino")]]), new Rule(44, new FunApp("Refine",[]),[],[[new Terminal("Refinas")]]), new Rule(43, new FunApp("Refine",[]),[],[[new Terminal("Refina")]]), new Rule(42, new FunApp("Refine",[]),[],[[new Terminal("Refinamos")]]), new Rule(41, new FunApp("Refine",[]),[],[[new Terminal("Refináis")]]), new Rule(40, new FunApp("Refine",[]),[],[[new Terminal("Refinan")]]), new Rule(39, new FunApp("Refine",[]),[],[[new Terminal("Refine")]]), new Rule(38, new FunApp("Refine",[]),[],[[new Terminal("Refines")]]), new Rule(37, new FunApp("Refine",[]),[],[[new Terminal("Refine")]]), new Rule(36, new FunApp("Refine",[]),[],[[new Terminal("Refinemos")]]), new Rule(35, new FunApp("Refine",[]),[],[[new Terminal("Refinéis")]]), new Rule(34, new FunApp("Refine",[]),[],[[new Terminal("Refinen")]]), new Rule(33, new FunApp("Refine",[]),[],[[new Terminal("Refina")]]), new Rule(32, new FunApp("Refine",[]),[],[[new Terminal("Refinemos")]]), new Rule(31, new FunApp("Refine",[]),[],[[new Terminal("Refinad")]]), new Rule(30, new FunApp("Refine",[]),[],[[new Terminal("Refinado")]]), new Rule(29, new FunApp("Refine",[]),[],[[new Terminal("Refinados")]]), new Rule(28, new FunApp("Refine",[]),[],[[new Terminal("Refinada")]]), new Rule(27, new FunApp("Refine",[]),[],[[new Terminal("Refinadas")]]), new Rule(26, new FunApp("Refine",[]),[],[[new Terminal("Refinando")]]), new Rule(20, new FunApp("Redo",[]),[],[[new Terminal("rehacer")]]), new Rule(46, new FunApp("Redo",[]),[],[[new Terminal("rehacer")]]), new Rule(45, new FunApp("Redo",[]),[],[[new Terminal("rehago")]]), new Rule(44, new FunApp("Redo",[]),[],[[new Terminal("rehaces")]]), new Rule(43, new FunApp("Redo",[]),[],[[new Terminal("rehace")]]), new Rule(42, new FunApp("Redo",[]),[],[[new Terminal("rehacemos")]]), new Rule(41, new FunApp("Redo",[]),[],[[new Terminal("rehacéis")]]), new Rule(40, new FunApp("Redo",[]),[],[[new Terminal("rehacen")]]), new Rule(39, new FunApp("Redo",[]),[],[[new Terminal("rehaga")]]), new Rule(38, new FunApp("Redo",[]),[],[[new Terminal("rehagas")]]), new Rule(37, new FunApp("Redo",[]),[],[[new Terminal("rehaga")]]), new Rule(36, new FunApp("Redo",[]),[],[[new Terminal("rehagamos")]]), new Rule(35, new FunApp("Redo",[]),[],[[new Terminal("rehagáis")]]), new Rule(34, new FunApp("Redo",[]),[],[[new Terminal("rehagan")]]), new Rule(33, new FunApp("Redo",[]),[],[[new Terminal("rehaz")]]), new Rule(32, new FunApp("Redo",[]),[],[[new Terminal("rehagamos")]]), new Rule(31, new FunApp("Redo",[]),[],[[new Terminal("rehaced")]]), new Rule(30, new FunApp("Redo",[]),[],[[new Terminal("rehecho")]]), new Rule(29, new FunApp("Redo",[]),[],[[new Terminal("rehechos")]]), new Rule(28, new FunApp("Redo",[]),[],[[new Terminal("rehecha")]]), new Rule(27, new FunApp("Redo",[]),[],[[new Terminal("rehechas")]]), new Rule(26, new FunApp("Redo",[]),[],[[new Terminal("rehaciendo")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[21, 23, 22],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aleatoriamente")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[20, 23, 22],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aleatoriamente")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[21, 19, 17],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aleatoriamente")]]), new Rule(18, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[20, 19, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("aleatoriamente")]]), new Rule(15, new FunApp("Previous",[]),[],[[new Terminal("anterior")]]), new Rule(14, new FunApp("Previous",[]),[],[[new Terminal("anteriores")]]), new Rule(13, new FunApp("Previous",[]),[],[[new Terminal("anterior")]]), new Rule(12, new FunApp("Previous",[]),[],[[new Terminal("anteriores")]]), new Rule(11, new FunApp("Previous",[]),[],[[new Terminal("anteriormente")]]), new Rule(10, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anterior")]]), new Rule(9, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anteriores")]]), new Rule(8, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anterior")]]), new Rule(7, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anteriores")]]), new Rule(6, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anteriormente")]]), new Rule(5, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anterior")]]), new Rule(4, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anteriores")]]), new Rule(3, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anterior")]]), new Rule(2, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anteriores")]]), new Rule(1, new FunApp("Previous",[]),[],[[new Terminal("más"), new Terminal("anteriormente")]]), new Rule(20, new FunApp("Paste",[]),[],[[new Terminal("Pegar")]]), new Rule(46, new FunApp("Paste",[]),[],[[new Terminal("Pegar")]]), new Rule(45, new FunApp("Paste",[]),[],[[new Terminal("Pego")]]), new Rule(44, new FunApp("Paste",[]),[],[[new Terminal("Pegas")]]), new Rule(43, new FunApp("Paste",[]),[],[[new Terminal("Pega")]]), new Rule(42, new FunApp("Paste",[]),[],[[new Terminal("Pegamos")]]), new Rule(41, new FunApp("Paste",[]),[],[[new Terminal("Pegáis")]]), new Rule(40, new FunApp("Paste",[]),[],[[new Terminal("Pegan")]]), new Rule(39, new FunApp("Paste",[]),[],[[new Terminal("Pegue")]]), new Rule(38, new FunApp("Paste",[]),[],[[new Terminal("Pegues")]]), new Rule(37, new FunApp("Paste",[]),[],[[new Terminal("Pegue")]]), new Rule(36, new FunApp("Paste",[]),[],[[new Terminal("Peguemos")]]), new Rule(35, new FunApp("Paste",[]),[],[[new Terminal("Peguéis")]]), new Rule(34, new FunApp("Paste",[]),[],[[new Terminal("Peguen")]]), new Rule(33, new FunApp("Paste",[]),[],[[new Terminal("Pega")]]), new Rule(32, new FunApp("Paste",[]),[],[[new Terminal("Peguemos")]]), new Rule(31, new FunApp("Paste",[]),[],[[new Terminal("Pegad")]]), new Rule(30, new FunApp("Paste",[]),[],[[new Terminal("Pegado")]]), new Rule(29, new FunApp("Paste",[]),[],[[new Terminal("Pegados")]]), new Rule(28, new FunApp("Paste",[]),[],[[new Terminal("Pegada")]]), new Rule(27, new FunApp("Paste",[]),[],[[new Terminal("Pegadas")]]), new Rule(26, new FunApp("Paste",[]),[],[[new Terminal("Pegando")]]), new Rule(20, new FunApp("Parse",[]),[],[[new Terminal("Analizar")]]), new Rule(46, new FunApp("Parse",[]),[],[[new Terminal("Analizar")]]), new Rule(45, new FunApp("Parse",[]),[],[[new Terminal("Analizo")]]), new Rule(44, new FunApp("Parse",[]),[],[[new Terminal("Analizas")]]), new Rule(43, new FunApp("Parse",[]),[],[[new Terminal("Analiza")]]), new Rule(42, new FunApp("Parse",[]),[],[[new Terminal("Analizamos")]]), new Rule(41, new FunApp("Parse",[]),[],[[new Terminal("Analizáis")]]), new Rule(40, new FunApp("Parse",[]),[],[[new Terminal("Analizan")]]), new Rule(39, new FunApp("Parse",[]),[],[[new Terminal("Analice")]]), new Rule(38, new FunApp("Parse",[]),[],[[new Terminal("Analices")]]), new Rule(37, new FunApp("Parse",[]),[],[[new Terminal("Analice")]]), new Rule(36, new FunApp("Parse",[]),[],[[new Terminal("Analicemos")]]), new Rule(35, new FunApp("Parse",[]),[],[[new Terminal("Analicéis")]]), new Rule(34, new FunApp("Parse",[]),[],[[new Terminal("Analicen")]]), new Rule(33, new FunApp("Parse",[]),[],[[new Terminal("Analiza")]]), new Rule(32, new FunApp("Parse",[]),[],[[new Terminal("Analicemos")]]), new Rule(31, new FunApp("Parse",[]),[],[[new Terminal("Analizad")]]), new Rule(30, new FunApp("Parse",[]),[],[[new Terminal("sintácticamente")]]), new Rule(29, new FunApp("Parse",[]),[],[[new Terminal("sintácticamentos")]]), new Rule(28, new FunApp("Parse",[]),[],[[new Terminal("sintácticamenta")]]), new Rule(27, new FunApp("Parse",[]),[],[[new Terminal("sintácticamentas")]]), new Rule(26, new FunApp("Parse",[]),[],[[new Terminal("Analizando")]]), new Rule(22, new FunApp("Page",[]),[],[[new Terminal("página")]]), new Rule(78, new FunApp("Page",[]),[],[[new Terminal("páginas")]]), new Rule(17, new FunApp("Norwegian",[]),[],[[new Terminal("Noruego")]]), new Rule(16, new FunApp("Norwegian",[]),[],[[new Terminal("Noruegos")]]), new Rule(17, new FunApp("Node",[]),[],[[new Terminal("nodo")]]), new Rule(16, new FunApp("Node",[]),[],[[new Terminal("nodos")]]), new Rule(15, new FunApp("Next",[]),[],[[new Terminal("siguiente")]]), new Rule(14, new FunApp("Next",[]),[],[[new Terminal("siguientes")]]), new Rule(13, new FunApp("Next",[]),[],[[new Terminal("siguiente")]]), new Rule(12, new FunApp("Next",[]),[],[[new Terminal("siguientes")]]), new Rule(11, new FunApp("Next",[]),[],[[new Terminal("siguientemente")]]), new Rule(10, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguiente")]]), new Rule(9, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguientes")]]), new Rule(8, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguiente")]]), new Rule(7, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguientes")]]), new Rule(6, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguientemente")]]), new Rule(5, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguiente")]]), new Rule(4, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguientes")]]), new Rule(3, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguiente")]]), new Rule(2, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguientes")]]), new Rule(1, new FunApp("Next",[]),[],[[new Terminal("más"), new Terminal("siguientemente")]]), new Rule(17, new FunApp("Language",[]),[],[[new Terminal("lenguaje")]]), new Rule(16, new FunApp("Language",[]),[],[[new Terminal("lenguajes")]]), new Rule(18, new FunApp("Label",[new Arg(0)]),[77],[[new ArgProj(0, 0)]]), new Rule(77, new Arg(0),[22],[[new ArgProj(0, 0)]]), new Rule(77, new Arg(0),[17],[[new ArgProj(0, 0)]]), new Rule(17, new FunApp("Italian",[]),[],[[new Terminal("Italiano")]]), new Rule(16, new FunApp("Italian",[]),[],[[new Terminal("Italianos")]]), new Rule(17, new FunApp("Integer_N",[]),[],[[new Terminal("número"), new Terminal("entero")]]), new Rule(16, new FunApp("Integer_N",[]),[],[[new Terminal("números"), new Terminal("entero")]]), new Rule(76, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(75, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(74, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(73, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(72, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(71, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(70, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(69, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(68, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(67, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(66, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(65, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(64, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(63, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(62, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(61, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(60, new FunApp("IndefSgDet",[]),[],[[new Terminal("un")]]), new Rule(19, new FunApp("IndefSgDet",[]),[],[[new Terminal("un")]]), new Rule(59, new FunApp("IndefSgDet",[]),[],[[new Terminal("de"), new Terminal("un")]]), new Rule(58, new FunApp("IndefSgDet",[]),[],[[new Terminal("a"), new Terminal("un")]]), new Rule(57, new FunApp("IndefSgDet",[]),[],[[new Terminal("una")]]), new Rule(23, new FunApp("IndefSgDet",[]),[],[[new Terminal("una")]]), new Rule(56, new FunApp("IndefSgDet",[]),[],[[new Terminal("de"), new Terminal("una")]]), new Rule(55, new FunApp("IndefSgDet",[]),[],[[new Terminal("a"), new Terminal("una")]]), new Rule(54, new FunApp("IndefSgDet",[]),[],[[new Terminal("unos")]]), new Rule(53, new FunApp("IndefSgDet",[]),[],[[new Terminal("unos")]]), new Rule(52, new FunApp("IndefSgDet",[]),[],[[new Terminal("de"), new Terminal("unos")]]), new Rule(51, new FunApp("IndefSgDet",[]),[],[[new Terminal("a"), new Terminal("unos")]]), new Rule(50, new FunApp("IndefSgDet",[]),[],[[new Terminal("unas")]]), new Rule(49, new FunApp("IndefSgDet",[]),[],[[new Terminal("unas")]]), new Rule(48, new FunApp("IndefSgDet",[]),[],[[new Terminal("de"), new Terminal("unas")]]), new Rule(47, new FunApp("IndefSgDet",[]),[],[[new Terminal("a"), new Terminal("unas")]]), new Rule(76, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(75, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(74, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(73, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(72, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(71, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(70, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(69, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(68, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(67, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(66, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(65, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(64, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(63, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(62, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(61, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(60, new FunApp("IndefPlDet",[]),[],[[new Terminal("un")]]), new Rule(19, new FunApp("IndefPlDet",[]),[],[[new Terminal("un")]]), new Rule(59, new FunApp("IndefPlDet",[]),[],[[new Terminal("de"), new Terminal("un")]]), new Rule(58, new FunApp("IndefPlDet",[]),[],[[new Terminal("a"), new Terminal("un")]]), new Rule(57, new FunApp("IndefPlDet",[]),[],[[new Terminal("una")]]), new Rule(23, new FunApp("IndefPlDet",[]),[],[[new Terminal("una")]]), new Rule(56, new FunApp("IndefPlDet",[]),[],[[new Terminal("de"), new Terminal("una")]]), new Rule(55, new FunApp("IndefPlDet",[]),[],[[new Terminal("a"), new Terminal("una")]]), new Rule(54, new FunApp("IndefPlDet",[]),[],[[new Terminal("unos")]]), new Rule(53, new FunApp("IndefPlDet",[]),[],[[new Terminal("unos")]]), new Rule(52, new FunApp("IndefPlDet",[]),[],[[new Terminal("de"), new Terminal("unos")]]), new Rule(51, new FunApp("IndefPlDet",[]),[],[[new Terminal("a"), new Terminal("unos")]]), new Rule(50, new FunApp("IndefPlDet",[]),[],[[new Terminal("unas")]]), new Rule(49, new FunApp("IndefPlDet",[]),[],[[new Terminal("unas")]]), new Rule(48, new FunApp("IndefPlDet",[]),[],[[new Terminal("de"), new Terminal("unas")]]), new Rule(47, new FunApp("IndefPlDet",[]),[],[[new Terminal("a"), new Terminal("unas")]]), new Rule(17, new FunApp("German",[]),[],[[new Terminal("Alemán")]]), new Rule(16, new FunApp("German",[]),[],[[new Terminal("Alemánes")]]), new Rule(17, new FunApp("French",[]),[],[[new Terminal("Francés")]]), new Rule(16, new FunApp("French",[]),[],[[new Terminal("Francéses")]]), new Rule(17, new FunApp("Float_N",[]),[],[[new Terminal("número"), new Terminal("real")]]), new Rule(16, new FunApp("Float_N",[]),[],[[new Terminal("números"), new Terminal("real")]]), new Rule(17, new FunApp("Finnish",[]),[],[[new Terminal("Finlandés")]]), new Rule(16, new FunApp("Finnish",[]),[],[[new Terminal("Finlandéses")]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[13, 22],[[new Terminal("no"), new Terminal("hay"), new Terminal("una"), new ArgProj(1, 0), new ArgProj(0, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[15, 17],[[new Terminal("no"), new Terminal("hay"), new Terminal("un"), new ArgProj(1, 0), new ArgProj(0, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[25, 22],[[new Terminal("no"), new Terminal("hay"), new Terminal("una"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(18, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[24, 17],[[new Terminal("no"), new Terminal("hay"), new Terminal("un"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(20, new FunApp("Enter",[]),[],[[new Terminal("introducir")]]), new Rule(46, new FunApp("Enter",[]),[],[[new Terminal("introducir")]]), new Rule(45, new FunApp("Enter",[]),[],[[new Terminal("introduzco")]]), new Rule(44, new FunApp("Enter",[]),[],[[new Terminal("introduces")]]), new Rule(43, new FunApp("Enter",[]),[],[[new Terminal("introduce")]]), new Rule(42, new FunApp("Enter",[]),[],[[new Terminal("introducimos")]]), new Rule(41, new FunApp("Enter",[]),[],[[new Terminal("introducís")]]), new Rule(40, new FunApp("Enter",[]),[],[[new Terminal("introducen")]]), new Rule(39, new FunApp("Enter",[]),[],[[new Terminal("introduzca")]]), new Rule(38, new FunApp("Enter",[]),[],[[new Terminal("introduzcas")]]), new Rule(37, new FunApp("Enter",[]),[],[[new Terminal("introduzca")]]), new Rule(36, new FunApp("Enter",[]),[],[[new Terminal("introduzcamos")]]), new Rule(35, new FunApp("Enter",[]),[],[[new Terminal("introduzcáis")]]), new Rule(34, new FunApp("Enter",[]),[],[[new Terminal("introduzcan")]]), new Rule(33, new FunApp("Enter",[]),[],[[new Terminal("introduce")]]), new Rule(32, new FunApp("Enter",[]),[],[[new Terminal("introduzcamos")]]), new Rule(31, new FunApp("Enter",[]),[],[[new Terminal("introducid")]]), new Rule(30, new FunApp("Enter",[]),[],[[new Terminal("introducido")]]), new Rule(29, new FunApp("Enter",[]),[],[[new Terminal("introducidos")]]), new Rule(28, new FunApp("Enter",[]),[],[[new Terminal("introducida")]]), new Rule(27, new FunApp("Enter",[]),[],[[new Terminal("introducidas")]]), new Rule(26, new FunApp("Enter",[]),[],[[new Terminal("introduciendo")]]), new Rule(17, new FunApp("English",[]),[],[[new Terminal("Inglés")]]), new Rule(16, new FunApp("English",[]),[],[[new Terminal("Ingléses")]]), new Rule(20, new FunApp("Delete",[]),[],[[new Terminal("Borrar")]]), new Rule(46, new FunApp("Delete",[]),[],[[new Terminal("Borrar")]]), new Rule(45, new FunApp("Delete",[]),[],[[new Terminal("Borro")]]), new Rule(44, new FunApp("Delete",[]),[],[[new Terminal("Borras")]]), new Rule(43, new FunApp("Delete",[]),[],[[new Terminal("Borra")]]), new Rule(42, new FunApp("Delete",[]),[],[[new Terminal("Borramos")]]), new Rule(41, new FunApp("Delete",[]),[],[[new Terminal("Borráis")]]), new Rule(40, new FunApp("Delete",[]),[],[[new Terminal("Borran")]]), new Rule(39, new FunApp("Delete",[]),[],[[new Terminal("Borre")]]), new Rule(38, new FunApp("Delete",[]),[],[[new Terminal("Borres")]]), new Rule(37, new FunApp("Delete",[]),[],[[new Terminal("Borre")]]), new Rule(36, new FunApp("Delete",[]),[],[[new Terminal("Borremos")]]), new Rule(35, new FunApp("Delete",[]),[],[[new Terminal("Borréis")]]), new Rule(34, new FunApp("Delete",[]),[],[[new Terminal("Borren")]]), new Rule(33, new FunApp("Delete",[]),[],[[new Terminal("Borra")]]), new Rule(32, new FunApp("Delete",[]),[],[[new Terminal("Borremos")]]), new Rule(31, new FunApp("Delete",[]),[],[[new Terminal("Borrad")]]), new Rule(30, new FunApp("Delete",[]),[],[[new Terminal("Borrado")]]), new Rule(29, new FunApp("Delete",[]),[],[[new Terminal("Borrados")]]), new Rule(28, new FunApp("Delete",[]),[],[[new Terminal("Borrada")]]), new Rule(27, new FunApp("Delete",[]),[],[[new Terminal("Borradas")]]), new Rule(26, new FunApp("Delete",[]),[],[[new Terminal("Borrando")]]), new Rule(76, new FunApp("DefSgDet",[]),[],[[new Terminal("el")]]), new Rule(75, new FunApp("DefSgDet",[]),[],[[new Terminal("el")]]), new Rule(74, new FunApp("DefSgDet",[]),[],[[new Terminal("del")]]), new Rule(73, new FunApp("DefSgDet",[]),[],[[new Terminal("al")]]), new Rule(72, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(71, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(70, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(69, new FunApp("DefSgDet",[]),[],[[new Terminal("a"), new Terminal("la")]]), new Rule(68, new FunApp("DefSgDet",[]),[],[[new Terminal("los")]]), new Rule(67, new FunApp("DefSgDet",[]),[],[[new Terminal("los")]]), new Rule(66, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("los")]]), new Rule(65, new FunApp("DefSgDet",[]),[],[[new Terminal("a"), new Terminal("los")]]), new Rule(64, new FunApp("DefSgDet",[]),[],[[new Terminal("las")]]), new Rule(63, new FunApp("DefSgDet",[]),[],[[new Terminal("las")]]), new Rule(62, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("las")]]), new Rule(61, new FunApp("DefSgDet",[]),[],[[new Terminal("a"), new Terminal("las")]]), new Rule(60, new FunApp("DefSgDet",[]),[],[[new Terminal("el")]]), new Rule(19, new FunApp("DefSgDet",[]),[],[[new Terminal("el")]]), new Rule(59, new FunApp("DefSgDet",[]),[],[[new Terminal("del")]]), new Rule(58, new FunApp("DefSgDet",[]),[],[[new Terminal("al")]]), new Rule(57, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(23, new FunApp("DefSgDet",[]),[],[[new Terminal("la")]]), new Rule(56, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(55, new FunApp("DefSgDet",[]),[],[[new Terminal("a"), new Terminal("la")]]), new Rule(54, new FunApp("DefSgDet",[]),[],[[new Terminal("los")]]), new Rule(53, new FunApp("DefSgDet",[]),[],[[new Terminal("los")]]), new Rule(52, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("los")]]), new Rule(51, new FunApp("DefSgDet",[]),[],[[new Terminal("a"), new Terminal("los")]]), new Rule(50, new FunApp("DefSgDet",[]),[],[[new Terminal("las")]]), new Rule(49, new FunApp("DefSgDet",[]),[],[[new Terminal("las")]]), new Rule(48, new FunApp("DefSgDet",[]),[],[[new Terminal("de"), new Terminal("las")]]), new Rule(47, new FunApp("DefSgDet",[]),[],[[new Terminal("a"), new Terminal("las")]]), new Rule(76, new FunApp("DefPlDet",[]),[],[[new Terminal("el")]]), new Rule(75, new FunApp("DefPlDet",[]),[],[[new Terminal("el")]]), new Rule(74, new FunApp("DefPlDet",[]),[],[[new Terminal("del")]]), new Rule(73, new FunApp("DefPlDet",[]),[],[[new Terminal("al")]]), new Rule(72, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(71, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(70, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(69, new FunApp("DefPlDet",[]),[],[[new Terminal("a"), new Terminal("la")]]), new Rule(68, new FunApp("DefPlDet",[]),[],[[new Terminal("los")]]), new Rule(67, new FunApp("DefPlDet",[]),[],[[new Terminal("los")]]), new Rule(66, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("los")]]), new Rule(65, new FunApp("DefPlDet",[]),[],[[new Terminal("a"), new Terminal("los")]]), new Rule(64, new FunApp("DefPlDet",[]),[],[[new Terminal("las")]]), new Rule(63, new FunApp("DefPlDet",[]),[],[[new Terminal("las")]]), new Rule(62, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("las")]]), new Rule(61, new FunApp("DefPlDet",[]),[],[[new Terminal("a"), new Terminal("las")]]), new Rule(60, new FunApp("DefPlDet",[]),[],[[new Terminal("el")]]), new Rule(19, new FunApp("DefPlDet",[]),[],[[new Terminal("el")]]), new Rule(59, new FunApp("DefPlDet",[]),[],[[new Terminal("del")]]), new Rule(58, new FunApp("DefPlDet",[]),[],[[new Terminal("al")]]), new Rule(57, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(23, new FunApp("DefPlDet",[]),[],[[new Terminal("la")]]), new Rule(56, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("la")]]), new Rule(55, new FunApp("DefPlDet",[]),[],[[new Terminal("a"), new Terminal("la")]]), new Rule(54, new FunApp("DefPlDet",[]),[],[[new Terminal("los")]]), new Rule(53, new FunApp("DefPlDet",[]),[],[[new Terminal("los")]]), new Rule(52, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("los")]]), new Rule(51, new FunApp("DefPlDet",[]),[],[[new Terminal("a"), new Terminal("los")]]), new Rule(50, new FunApp("DefPlDet",[]),[],[[new Terminal("las")]]), new Rule(49, new FunApp("DefPlDet",[]),[],[[new Terminal("las")]]), new Rule(48, new FunApp("DefPlDet",[]),[],[[new Terminal("de"), new Terminal("las")]]), new Rule(47, new FunApp("DefPlDet",[]),[],[[new Terminal("a"), new Terminal("las")]]), new Rule(17, new FunApp("Danish",[]),[],[[new Terminal("Danés")]]), new Rule(16, new FunApp("Danish",[]),[],[[new Terminal("Danéses")]]), new Rule(20, new FunApp("Cut",[]),[],[[new Terminal("Cortar")]]), new Rule(46, new FunApp("Cut",[]),[],[[new Terminal("Cortar")]]), new Rule(45, new FunApp("Cut",[]),[],[[new Terminal("Corto")]]), new Rule(44, new FunApp("Cut",[]),[],[[new Terminal("Cortas")]]), new Rule(43, new FunApp("Cut",[]),[],[[new Terminal("Corta")]]), new Rule(42, new FunApp("Cut",[]),[],[[new Terminal("Cortamos")]]), new Rule(41, new FunApp("Cut",[]),[],[[new Terminal("Cortáis")]]), new Rule(40, new FunApp("Cut",[]),[],[[new Terminal("Cortan")]]), new Rule(39, new FunApp("Cut",[]),[],[[new Terminal("Corte")]]), new Rule(38, new FunApp("Cut",[]),[],[[new Terminal("Cortes")]]), new Rule(37, new FunApp("Cut",[]),[],[[new Terminal("Corte")]]), new Rule(36, new FunApp("Cut",[]),[],[[new Terminal("Cortemos")]]), new Rule(35, new FunApp("Cut",[]),[],[[new Terminal("Cortéis")]]), new Rule(34, new FunApp("Cut",[]),[],[[new Terminal("Corten")]]), new Rule(33, new FunApp("Cut",[]),[],[[new Terminal("Corta")]]), new Rule(32, new FunApp("Cut",[]),[],[[new Terminal("Cortemos")]]), new Rule(31, new FunApp("Cut",[]),[],[[new Terminal("Cortad")]]), new Rule(30, new FunApp("Cut",[]),[],[[new Terminal("Cortado")]]), new Rule(29, new FunApp("Cut",[]),[],[[new Terminal("Cortados")]]), new Rule(28, new FunApp("Cut",[]),[],[[new Terminal("Cortada")]]), new Rule(27, new FunApp("Cut",[]),[],[[new Terminal("Cortadas")]]), new Rule(26, new FunApp("Cut",[]),[],[[new Terminal("Cortando")]]), new Rule(20, new FunApp("Copy",[]),[],[[new Terminal("Copiar")]]), new Rule(46, new FunApp("Copy",[]),[],[[new Terminal("Copiar")]]), new Rule(45, new FunApp("Copy",[]),[],[[new Terminal("Copío")]]), new Rule(44, new FunApp("Copy",[]),[],[[new Terminal("Copías")]]), new Rule(43, new FunApp("Copy",[]),[],[[new Terminal("Copía")]]), new Rule(42, new FunApp("Copy",[]),[],[[new Terminal("Copiamos")]]), new Rule(41, new FunApp("Copy",[]),[],[[new Terminal("Copiáis")]]), new Rule(40, new FunApp("Copy",[]),[],[[new Terminal("Copían")]]), new Rule(39, new FunApp("Copy",[]),[],[[new Terminal("Copíe")]]), new Rule(38, new FunApp("Copy",[]),[],[[new Terminal("Copíes")]]), new Rule(37, new FunApp("Copy",[]),[],[[new Terminal("Copíe")]]), new Rule(36, new FunApp("Copy",[]),[],[[new Terminal("Copiemos")]]), new Rule(35, new FunApp("Copy",[]),[],[[new Terminal("Copiéis")]]), new Rule(34, new FunApp("Copy",[]),[],[[new Terminal("Copíen")]]), new Rule(33, new FunApp("Copy",[]),[],[[new Terminal("Copía")]]), new Rule(32, new FunApp("Copy",[]),[],[[new Terminal("Copiemos")]]), new Rule(31, new FunApp("Copy",[]),[],[[new Terminal("Copiad")]]), new Rule(30, new FunApp("Copy",[]),[],[[new Terminal("Copiado")]]), new Rule(29, new FunApp("Copy",[]),[],[[new Terminal("Copiados")]]), new Rule(28, new FunApp("Copy",[]),[],[[new Terminal("Copiada")]]), new Rule(27, new FunApp("Copy",[]),[],[[new Terminal("Copiadas")]]), new Rule(26, new FunApp("Copy",[]),[],[[new Terminal("Copiando")]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 23, 13, 22],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 23, 13, 22],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 19, 15, 17],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 19, 15, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(3, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 23, 25, 22],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 23, 25, 22],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[21, 19, 24, 17],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[20, 19, 24, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[21, 23, 22],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[20, 23, 22],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[21, 19, 17],[[new ArgProj(0, 0), new Terminal("&+"), new Terminal("se"), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(18, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[20, 19, 17],[[new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(17, new FunApp("Bulgarian",[]),[],[[new Terminal("Búlgaro")]]), new Rule(16, new FunApp("Bulgarian",[]),[],[[new Terminal("Búlgaros")]]), new Rule(15, new FunApp("Available",[]),[],[[new Terminal("disponible")]]), new Rule(14, new FunApp("Available",[]),[],[[new Terminal("disponibles")]]), new Rule(13, new FunApp("Available",[]),[],[[new Terminal("disponible")]]), new Rule(12, new FunApp("Available",[]),[],[[new Terminal("disponibles")]]), new Rule(11, new FunApp("Available",[]),[],[[new Terminal("disponiblemente")]]), new Rule(10, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponible")]]), new Rule(9, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponibles")]]), new Rule(8, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponible")]]), new Rule(7, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponibles")]]), new Rule(6, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponiblemente")]]), new Rule(5, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponible")]]), new Rule(4, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponibles")]]), new Rule(3, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponible")]]), new Rule(2, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponibles")]]), new Rule(1, new FunApp("Available",[]),[],[[new Terminal("más"), new Terminal("disponiblemente")]])],{Adjective:[24, 15, 10, 5, 14, 9, 4, 25, 13, 8, 3, 12, 7, 2, 11, 6, 1], Determiner:[76, 60, 68, 54, 72, 57, 64, 50, 75, 19, 67, 53, 71, 23, 63, 49, 74, 59, 66, 52, 70, 56, 62, 48, 73, 58, 65, 51, 69, 55, 61, 47], Float:[-3], Int:[-2], Noun:[77, 17, 22, 16, 78], Sentence:[18], String:[-1], Verb:[20, 21, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26], _Var:[-4]})), EditorSwe: new GFConcrete({coding: "utf8"},{Available: function(cs){return new Arr(new Suffix("tillgänglig", Editor.concretes["EditorSwe"].rule("_0", cs)), new Int(1));}, Bulgarian: function(cs){return new Arr(new Arr(new Arr(new Suffix("Bulgariska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Bulgariskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Bulgariskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Bulgariskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Command: function(cs){return new Arr(new Seq(Editor.concretes["EditorSwe"].rule("_16", cs), Editor.concretes["EditorSwe"].rule("_17", cs), Editor.concretes["EditorSwe"].rule("_23", cs), Editor.concretes["EditorSwe"].rule("_47", cs), Editor.concretes["EditorSwe"].rule("_62", cs), Editor.concretes["EditorSwe"].rule("_64", cs)));}, CommandAdj: function(cs){return new Arr(new Seq(Editor.concretes["EditorSwe"].rule("_16", cs), Editor.concretes["EditorSwe"].rule("_17", cs), Editor.concretes["EditorSwe"].rule("_67", cs).sel(new Int(1)).sel(Editor.concretes["EditorSwe"].rule("_69", cs)),(new Arr(new Seq(Editor.concretes["EditorSwe"].rule("_75", cs).sel(Editor.concretes["EditorSwe"].rule("_80", cs).sel(Editor.concretes["EditorSwe"].rule("_86", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_86", cs).sel(new Int(1)))), Editor.concretes["EditorSwe"].rule("_95", cs)), new Seq(Editor.concretes["EditorSwe"].rule("_75", cs).sel(Editor.concretes["EditorSwe"].rule("_80", cs).sel(Editor.concretes["EditorSwe"].rule("_97", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_97", cs).sel(new Int(1)))), Editor.concretes["EditorSwe"].rule("_95", cs)), new Seq(Editor.concretes["EditorSwe"].rule("_75", cs).sel(Editor.concretes["EditorSwe"].rule("_80", cs).sel(Editor.concretes["EditorSwe"].rule("_105", cs)).sel(Editor.concretes["EditorSwe"].rule("_107", cs))), Editor.concretes["EditorSwe"].rule("_93", cs).sel(new Int(1)).sel(new Int(0))))).sel(Editor.concretes["EditorSwe"].rule("_38", cs).sel(Editor.concretes["EditorSwe"].rule("_114", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_114", cs).sel(new Int(1))).sel(Editor.concretes["EditorSwe"].rule("_114", cs).sel(new Int(2)))), Editor.concretes["EditorSwe"].rule("_50", cs).sel(Editor.concretes["EditorSwe"].rule("_105", cs)).sel(Editor.concretes["EditorSwe"].rule("_107", cs)), Editor.concretes["EditorSwe"].rule("_64", cs)));}, Copy: function(cs){return new Arr(new Suffix("Kopiera", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Cut: function(cs){return new Arr(new Suffix("Klipp", Editor.concretes["EditorSwe"].rule("_129", cs)), new Str("ut"), new Int(0));}, Danish: function(cs){return new Arr(new Arr(new Arr(new Suffix("Danska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Danskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Danskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Danskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, DefPlDet: function(cs){return Editor.concretes["EditorSwe"].rule("_152", cs);}, DefSgDet: function(cs){return Editor.concretes["EditorSwe"].rule("_152", cs);}, Delete: function(cs){return new Arr(new Suffix("Radera", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, English: function(cs){return new Arr(new Arr(new Arr(new Suffix("Engelska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Engelskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Engelskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Engelskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Enter: function(cs){return new Arr(new Suffix("Skriv", new Arr(new Str("er"), new Str("s"), new Str(""), new Str("s"), new Str("a"), new Str("as"), new Str("d"), new Str("ds"), new Str("t"), new Str("ts"), new Str("da"), new Str("das"), new Str("da"), new Str("das"), new Str("da"), new Str("das"))), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, ErrorMessage: function(cs){return new Arr(new Seq(new Str("det"), new Str("finns"), new Str("inte"),(new Arr(new Str("en"), new Str("ett"))).sel(Editor.concretes["EditorSwe"].rule("_39", cs)),(new Arr(new Seq(Editor.concretes["EditorSwe"].rule("_173", cs).sel(Editor.concretes["EditorSwe"].rule("_177", cs).sel(Editor.concretes["EditorSwe"].rule("_183", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_183", cs).sel(new Int(1)))), Editor.concretes["EditorSwe"].rule("_189", cs)), new Seq(Editor.concretes["EditorSwe"].rule("_173", cs).sel(Editor.concretes["EditorSwe"].rule("_177", cs).sel(Editor.concretes["EditorSwe"].rule("_191", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_191", cs).sel(new Int(1)))), Editor.concretes["EditorSwe"].rule("_189", cs)), new Seq(Editor.concretes["EditorSwe"].rule("_173", cs).sel(Editor.concretes["EditorSwe"].rule("_177", cs).sel(Editor.concretes["EditorSwe"].rule("_198", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_198", cs).sel(new Int(1)))), Editor.concretes["EditorSwe"].rule("_20", cs).sel(new Int(0))))).sel(Editor.concretes["EditorSwe"].rule("_38", cs).sel(Editor.concretes["EditorSwe"].rule("_207", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_207", cs).sel(new Int(1))).sel(Editor.concretes["EditorSwe"].rule("_207", cs).sel(new Int(2))))));}, Finnish: function(cs){return new Arr(new Arr(new Arr(new Suffix("Finska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Finskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Finskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Finskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Float_N: function(cs){return new Arr(new Arr(new Arr(Editor.concretes["EditorSwe"].rule("_225", cs), new Suffix("flyttalet", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(Editor.concretes["EditorSwe"].rule("_225", cs), new Suffix("flyttalen", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(1));}, French: function(cs){return new Arr(new Arr(new Arr(new Suffix("Franska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Franskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Franskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Franskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, German: function(cs){return new Arr(new Arr(new Arr(new Suffix("Tyska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Tyskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Tyskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Tyskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, IndefPlDet: function(cs){return Editor.concretes["EditorSwe"].rule("_255", cs);}, IndefSgDet: function(cs){return Editor.concretes["EditorSwe"].rule("_255", cs);}, Integer_N: function(cs){return new Arr(new Arr(new Arr(Editor.concretes["EditorSwe"].rule("_256", cs), new Suffix("heltalet", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(Editor.concretes["EditorSwe"].rule("_256", cs), new Suffix("heltalen", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(1));}, Italian: function(cs){return new Arr(new Arr(new Arr(new Suffix("Italienska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Italienskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Italienskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Italienskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Label: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_168", cs).sel(new Int(0)).sel(new Int(0)));}, Language: function(cs){return new Arr(new Arr(new Arr(Editor.concretes["EditorSwe"].rule("_274", cs), new Suffix("språket", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(Editor.concretes["EditorSwe"].rule("_274", cs), new Suffix("språken", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(1));}, Next: function(cs){return new Arr(new Suffix("näst", Editor.concretes["EditorSwe"].rule("_0", cs)), new Int(1));}, Node: function(cs){return new Arr(new Arr(new Arr(new Suffix("nod", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("noden", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("nodar", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("nodarna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Norwegian: function(cs){return new Arr(new Arr(new Arr(new Suffix("Norska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Norskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Norskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Norskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Page: function(cs){return new Arr(new Arr(new Arr(new Suffix("sida", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("sidan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("sidor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("sidorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Parse: function(cs){return new Arr(new Suffix("Parsa", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Paste: function(cs){return new Arr(new Suffix("Klistra", Editor.concretes["EditorSwe"].rule("_126", cs)), new Str("in"), new Int(0));}, Previous: function(cs){return new Arr(new Arr(new Str("föregående"), new Str("föregåendes"), new Str("föregående"), new Str("föregåendes"), new Str("föregående"), new Str("föregåendes"), new Str("föregående"), new Str("föregåendes"), new Str("föregående"), new Str("föregåendes"), Editor.concretes["EditorSwe"].rule("_48", cs), new Str("s"), Editor.concretes["EditorSwe"].rule("_48", cs), new Str("s"), new Str("a"), new Str("as")), new Int(1));}, RandomlyCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorSwe"].rule("_16", cs), Editor.concretes["EditorSwe"].rule("_17", cs), Editor.concretes["EditorSwe"].rule("_23", cs), Editor.concretes["EditorSwe"].rule("_47", cs), Editor.concretes["EditorSwe"].rule("_62", cs), Editor.concretes["EditorSwe"].rule("_64", cs), new Str("slumpmässigt")));}, Redo: function(cs){return new Arr(new Suffix("Upprepa", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Refine: function(cs){return new Arr(new Suffix("Raffinera", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Refinement: function(cs){return new Arr(new Arr(new Arr(new Suffix("raffinemang", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("raffinemangen", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("raffinemangar", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("raffinemangarna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Replace: function(cs){return new Arr(new Suffix("Ersätt", Editor.concretes["EditorSwe"].rule("_129", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Russian: function(cs){return new Arr(new Arr(new Arr(new Suffix("Ryska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Ryskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Ryskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Ryskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Select: function(cs){return new Arr(new Suffix("Välj", Editor.concretes["EditorSwe"].rule("_129", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Show: function(cs){return new Arr(new Suffix("Visa", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, SingleWordCommand: function(cs){return new Arr(new Seq(Editor.concretes["EditorSwe"].rule("_16", cs), Editor.concretes["EditorSwe"].rule("_17", cs),(new Arr(Editor.concretes["EditorSwe"].rule("_345", cs), Editor.concretes["EditorSwe"].rule("_345", cs), new Arr((new Arr(Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs), new Str("oss"))).sel(Editor.concretes["EditorSwe"].rule("_14", cs)),(new Arr(Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs), new Str("er"))).sel(Editor.concretes["EditorSwe"].rule("_14", cs)), Editor.concretes["EditorSwe"].rule("_344", cs)))).sel(Editor.concretes["EditorSwe"].rule("_76", cs).sel(new Int(0))).sel(Editor.concretes["EditorSwe"].rule("_76", cs).sel(new Int(1)))));}, Spanish: function(cs){return new Arr(new Arr(new Arr(new Suffix("Spanska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Spanskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Spanskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Spanskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, String_N: function(cs){return new Arr(new Arr(new Arr(new Suffix("sträng", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("strängen", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("strängar", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("strängarna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Swedish: function(cs){return new Arr(new Arr(new Arr(new Suffix("Svenska", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Svenskan", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("Svenskor", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("Svenskorna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, Tree: function(cs){return new Arr(new Arr(new Arr(Editor.concretes["EditorSwe"].rule("_382", cs), new Suffix("trädet", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(Editor.concretes["EditorSwe"].rule("_382", cs), new Suffix("träden", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(1));}, Undo: function(cs){return new Arr(new Suffix("Ångra", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Wrap: function(cs){return new Arr(new Suffix("Förpacka", Editor.concretes["EditorSwe"].rule("_126", cs)), Editor.concretes["EditorSwe"].rule("_48", cs), new Int(0));}, Wrapper: function(cs){return new Arr(new Arr(new Arr(new Suffix("förpackning", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("förpackningen", Editor.concretes["EditorSwe"].rule("_3", cs))), new Arr(new Suffix("förpackningar", Editor.concretes["EditorSwe"].rule("_3", cs)), new Suffix("förpackningarna", Editor.concretes["EditorSwe"].rule("_3", cs)))), new Int(0));}, _0: function(cs){return new Arr(new Str(""), new Str("s"), new Str("t"), new Str("ts"), new Str("a"), new Str("as"), new Str("a"), new Str("as"), new Str("a"), new Str("as"), new Str("are"), new Str("ares"), new Str("ast"), new Str("asts"), new Str("aste"), new Str("astes"));}, _104: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_85", cs), new Int(2));}, _105: function(cs){return Editor.concretes["EditorSwe"].rule("_104", cs).sel(new Int(0));}, _107: function(cs){return Editor.concretes["EditorSwe"].rule("_104", cs).sel(new Int(1));}, _114: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_39", cs), new Int(1), new Int(0));}, _12: function(cs){return cs[0].sel(new Int(0));}, _126: function(cs){return new Arr(new Str("r"), new Str("s"), new Str(""), new Str("s"), new Str(""), new Str("s"), new Str("d"), new Str("ds"), new Str("t"), new Str("ts"), new Str("de"), new Str("des"), new Str("de"), new Str("des"), new Str("de"), new Str("des"));}, _129: function(cs){return new Arr(new Str("er"), new Str("s"), new Str(""), new Str("s"), new Str("a"), new Str("as"), new Str("t"), new Str("ts"), new Str("t"), new Str("ts"), new Str("ta"), new Str("tas"), new Str("ta"), new Str("tas"), new Str("ta"), new Str("tas"));}, _13: function(cs){return new Arr(new Int(2), new Int(3), new Int(2));}, _14: function(cs){return cs[0].sel(new Int(2));}, _140: function(cs){return new Arr(new Str("n"), new Str("t"));}, _141: function(cs){return new Suffix("de", Editor.concretes["EditorSwe"].rule("_140", cs));}, _142: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_141", cs), Editor.concretes["EditorSwe"].rule("_141", cs));}, _143: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs));}, _144: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_141", cs), Editor.concretes["EditorSwe"].rule("_143", cs));}, _145: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_142", cs), Editor.concretes["EditorSwe"].rule("_144", cs));}, _146: function(cs){return new Arr(new Str(""), new Str(""));}, _147: function(cs){return new Suffix("de", Editor.concretes["EditorSwe"].rule("_146", cs));}, _148: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_147", cs), Editor.concretes["EditorSwe"].rule("_147", cs));}, _149: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_147", cs), Editor.concretes["EditorSwe"].rule("_143", cs));}, _15: function(cs){return Editor.concretes["EditorSwe"].rule("_13", cs).sel(Editor.concretes["EditorSwe"].rule("_14", cs));}, _150: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_148", cs), Editor.concretes["EditorSwe"].rule("_149", cs));}, _151: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_145", cs), Editor.concretes["EditorSwe"].rule("_150", cs));}, _152: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_151", cs), new Int(2));}, _16: function(cs){return Editor.concretes["EditorSwe"].rule("_12", cs).sel(Editor.concretes["EditorSwe"].rule("_15", cs));}, _168: function(cs){return Editor.concretes["EditorSwe"].rule("_12", cs).sel(new Int(0));}, _169: function(cs){return Editor.concretes["EditorSwe"].rule("_12", cs).sel(new Int(2));}, _17: function(cs){return cs[0].sel(new Int(1));}, _170: function(cs){return Editor.concretes["EditorSwe"].rule("_12", cs).sel(new Int(4));}, _171: function(cs){return Editor.concretes["EditorSwe"].rule("_12", cs).sel(new Int(6));}, _172: function(cs){return Editor.concretes["EditorSwe"].rule("_12", cs).sel(new Int(8));}, _173: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_168", cs), Editor.concretes["EditorSwe"].rule("_169", cs), Editor.concretes["EditorSwe"].rule("_170", cs), Editor.concretes["EditorSwe"].rule("_171", cs), Editor.concretes["EditorSwe"].rule("_172", cs));}, _174: function(cs){return Editor.concretes["EditorSwe"].rule("_76", cs).sel(Editor.concretes["EditorSwe"].rule("_39", cs));}, _175: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_174", cs), new Int(3), new Int(3));}, _176: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_174", cs), new Int(4), new Int(4));}, _177: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_175", cs), Editor.concretes["EditorSwe"].rule("_175", cs), Editor.concretes["EditorSwe"].rule("_176", cs));}, _178: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_39", cs), new Int(0));}, _179: function(cs){return Editor.concretes["EditorSwe"].rule("_178", cs).sel(new Int(0));}, _18: function(cs){return cs[1].sel(new Int(0));}, _180: function(cs){return Editor.concretes["EditorSwe"].rule("_52", cs).sel(Editor.concretes["EditorSwe"].rule("_179", cs));}, _181: function(cs){return Editor.concretes["EditorSwe"].rule("_178", cs).sel(new Int(1));}, _182: function(cs){return Editor.concretes["EditorSwe"].rule("_180", cs).sel(Editor.concretes["EditorSwe"].rule("_181", cs));}, _183: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_182", cs), new Int(0));}, _189: function(cs){return Editor.concretes["EditorSwe"].rule("_67", cs).sel(new Int(0));}, _19: function(cs){return Editor.concretes["EditorSwe"].rule("_18", cs).sel(new Int(0));}, _191: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_182", cs), new Int(1));}, _198: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_182", cs), new Int(2));}, _20: function(cs){return Editor.concretes["EditorSwe"].rule("_19", cs).sel(new Int(1));}, _207: function(cs){return new Arr(new Int(0), new Int(1), new Int(0));}, _21: function(cs){return Editor.concretes["EditorSwe"].rule("_20", cs).sel(new Int(1));}, _22: function(cs){return cs[2].sel(new Int(1));}, _225: function(cs){return new Suffix("flyttal", Editor.concretes["EditorSwe"].rule("_3", cs));}, _23: function(cs){return Editor.concretes["EditorSwe"].rule("_21", cs).sel(Editor.concretes["EditorSwe"].rule("_22", cs));}, _24: function(cs){return cs[2].sel(new Int(0));}, _248: function(cs){return new Arr(new Str("n"), new Str("tt"));}, _249: function(cs){return new Suffix("e", Editor.concretes["EditorSwe"].rule("_248", cs));}, _25: function(cs){return Editor.concretes["EditorSwe"].rule("_24", cs).sel(new Int(0));}, _250: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_143", cs), Editor.concretes["EditorSwe"].rule("_249", cs));}, _251: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_250", cs), Editor.concretes["EditorSwe"].rule("_250", cs));}, _252: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_143", cs), Editor.concretes["EditorSwe"].rule("_143", cs));}, _253: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_252", cs), Editor.concretes["EditorSwe"].rule("_252", cs));}, _254: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_251", cs), Editor.concretes["EditorSwe"].rule("_253", cs));}, _255: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_254", cs), new Int(0));}, _256: function(cs){return new Suffix("heltal", Editor.concretes["EditorSwe"].rule("_3", cs));}, _26: function(cs){return Editor.concretes["EditorSwe"].rule("_25", cs).sel(new Int(0));}, _27: function(cs){return Editor.concretes["EditorSwe"].rule("_26", cs).sel(new Int(0));}, _274: function(cs){return new Suffix("språk", Editor.concretes["EditorSwe"].rule("_3", cs));}, _28: function(cs){return Editor.concretes["EditorSwe"].rule("_25", cs).sel(new Int(1));}, _29: function(cs){return Editor.concretes["EditorSwe"].rule("_28", cs).sel(new Int(0));}, _3: function(cs){return new Arr(new Str(""), new Str("s"));}, _30: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_27", cs), Editor.concretes["EditorSwe"].rule("_27", cs), Editor.concretes["EditorSwe"].rule("_29", cs));}, _31: function(cs){return new Arr(new Int(0), new Int(0));}, _32: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_31", cs), Editor.concretes["EditorSwe"].rule("_31", cs));}, _33: function(cs){return new Arr(new Int(1), new Int(1));}, _34: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_33", cs), Editor.concretes["EditorSwe"].rule("_33", cs));}, _341: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs), new Str("mig"));}, _342: function(cs){return Editor.concretes["EditorSwe"].rule("_341", cs).sel(Editor.concretes["EditorSwe"].rule("_14", cs));}, _343: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs), new Str("sig"));}, _344: function(cs){return Editor.concretes["EditorSwe"].rule("_343", cs).sel(Editor.concretes["EditorSwe"].rule("_14", cs));}, _345: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_342", cs), Editor.concretes["EditorSwe"].rule("_64", cs), Editor.concretes["EditorSwe"].rule("_344", cs));}, _35: function(cs){return new Arr(new Int(1), new Int(2));}, _36: function(cs){return new Arr(new Int(2), new Int(2));}, _37: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_35", cs), Editor.concretes["EditorSwe"].rule("_36", cs));}, _38: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_32", cs), Editor.concretes["EditorSwe"].rule("_34", cs), Editor.concretes["EditorSwe"].rule("_37", cs));}, _382: function(cs){return new Suffix("träd", Editor.concretes["EditorSwe"].rule("_3", cs));}, _39: function(cs){return cs[1].sel(new Int(1));}, _40: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_39", cs), new Int(1), new Int(1));}, _401: function(cs){return new Arr(cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0], cs[0]);}, _403: function(cs){return new Arr(cs[0], cs[0]);}, _404: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_403", cs), Editor.concretes["EditorSwe"].rule("_403", cs));}, _405: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_404", cs), Editor.concretes["EditorSwe"].rule("_404", cs));}, _41: function(cs){return Editor.concretes["EditorSwe"].rule("_40", cs).sel(new Int(0));}, _42: function(cs){return Editor.concretes["EditorSwe"].rule("_38", cs).sel(Editor.concretes["EditorSwe"].rule("_41", cs));}, _43: function(cs){return Editor.concretes["EditorSwe"].rule("_40", cs).sel(new Int(1));}, _44: function(cs){return Editor.concretes["EditorSwe"].rule("_42", cs).sel(Editor.concretes["EditorSwe"].rule("_43", cs));}, _45: function(cs){return Editor.concretes["EditorSwe"].rule("_40", cs).sel(new Int(2));}, _46: function(cs){return Editor.concretes["EditorSwe"].rule("_44", cs).sel(Editor.concretes["EditorSwe"].rule("_45", cs));}, _47: function(cs){return Editor.concretes["EditorSwe"].rule("_30", cs).sel(Editor.concretes["EditorSwe"].rule("_46", cs));}, _48: function(cs){return new Seq();}, _49: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs));}, _50: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_49", cs), Editor.concretes["EditorSwe"].rule("_49", cs), Editor.concretes["EditorSwe"].rule("_49", cs));}, _51: function(cs){return new Arr(new Int(0), new Int(2));}, _52: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_51", cs), Editor.concretes["EditorSwe"].rule("_35", cs));}, _53: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_22", cs), new Int(0));}, _54: function(cs){return Editor.concretes["EditorSwe"].rule("_53", cs).sel(new Int(0));}, _55: function(cs){return Editor.concretes["EditorSwe"].rule("_52", cs).sel(Editor.concretes["EditorSwe"].rule("_54", cs));}, _56: function(cs){return Editor.concretes["EditorSwe"].rule("_53", cs).sel(new Int(1));}, _57: function(cs){return Editor.concretes["EditorSwe"].rule("_55", cs).sel(Editor.concretes["EditorSwe"].rule("_56", cs));}, _58: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_57", cs), new Int(2));}, _59: function(cs){return Editor.concretes["EditorSwe"].rule("_58", cs).sel(new Int(0));}, _60: function(cs){return Editor.concretes["EditorSwe"].rule("_50", cs).sel(Editor.concretes["EditorSwe"].rule("_59", cs));}, _61: function(cs){return Editor.concretes["EditorSwe"].rule("_58", cs).sel(new Int(1));}, _62: function(cs){return Editor.concretes["EditorSwe"].rule("_60", cs).sel(Editor.concretes["EditorSwe"].rule("_61", cs));}, _63: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_48", cs), Editor.concretes["EditorSwe"].rule("_48", cs), new Str("dig"));}, _64: function(cs){return Editor.concretes["EditorSwe"].rule("_63", cs).sel(Editor.concretes["EditorSwe"].rule("_14", cs));}, _67: function(cs){return Editor.concretes["EditorSwe"].rule("_19", cs).sel(new Int(0));}, _69: function(cs){return cs[3].sel(new Int(1));}, _71: function(cs){return Editor.concretes["EditorSwe"].rule("_24", cs).sel(new Int(2));}, _72: function(cs){return Editor.concretes["EditorSwe"].rule("_24", cs).sel(new Int(4));}, _73: function(cs){return Editor.concretes["EditorSwe"].rule("_24", cs).sel(new Int(6));}, _74: function(cs){return Editor.concretes["EditorSwe"].rule("_24", cs).sel(new Int(8));}, _75: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_25", cs), Editor.concretes["EditorSwe"].rule("_71", cs), Editor.concretes["EditorSwe"].rule("_72", cs), Editor.concretes["EditorSwe"].rule("_73", cs), Editor.concretes["EditorSwe"].rule("_74", cs));}, _76: function(cs){return new Arr(new Int(0), new Int(1));}, _77: function(cs){return Editor.concretes["EditorSwe"].rule("_76", cs).sel(Editor.concretes["EditorSwe"].rule("_69", cs));}, _78: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_77", cs), new Int(3), new Int(3));}, _79: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_77", cs), new Int(4), new Int(4));}, _80: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_78", cs), Editor.concretes["EditorSwe"].rule("_78", cs), Editor.concretes["EditorSwe"].rule("_79", cs));}, _81: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_69", cs), new Int(0));}, _82: function(cs){return Editor.concretes["EditorSwe"].rule("_81", cs).sel(new Int(0));}, _83: function(cs){return Editor.concretes["EditorSwe"].rule("_52", cs).sel(Editor.concretes["EditorSwe"].rule("_82", cs));}, _84: function(cs){return Editor.concretes["EditorSwe"].rule("_81", cs).sel(new Int(1));}, _85: function(cs){return Editor.concretes["EditorSwe"].rule("_83", cs).sel(Editor.concretes["EditorSwe"].rule("_84", cs));}, _86: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_85", cs), new Int(0));}, _92: function(cs){return cs[3].sel(new Int(0));}, _93: function(cs){return Editor.concretes["EditorSwe"].rule("_92", cs).sel(new Int(0));}, _94: function(cs){return Editor.concretes["EditorSwe"].rule("_93", cs).sel(new Int(0));}, _95: function(cs){return Editor.concretes["EditorSwe"].rule("_94", cs).sel(new Int(0));}, _97: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_85", cs), new Int(1));}, Adjective: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_401", cs), new Int(0));}, Determiner: function(cs){return new Arr(new Arr(Editor.concretes["EditorSwe"].rule("_405", cs), Editor.concretes["EditorSwe"].rule("_405", cs)), new Int(0));}, Noun: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_405", cs), new Int(0));}, Sentence: function(cs){return new Arr(cs[0]);}, Verb: function(cs){return new Arr(Editor.concretes["EditorSwe"].rule("_401", cs), cs[0], new Int(0));}, "Int": function(cs){return new Arr(cs[0]);}, "Float": function(cs){return new Arr(cs[0]);}, "String": function(cs){return new Arr(cs[0]);}}, new Parser("Sentence",[new Rule(27, new FunApp("Copy",[]),[],[[],[new Terminal("Kopiera")]]), new Rule(27, new FunApp("Cut",[]),[],[[new Terminal("ut")],[new Terminal("Klipp")]]), new Rule(27, new FunApp("Delete",[]),[],[[],[new Terminal("Radera")]]), new Rule(27, new FunApp("Enter",[]),[],[[],[new Terminal("Skriv")]]), new Rule(27, new FunApp("Parse",[]),[],[[],[new Terminal("Parsa")]]), new Rule(27, new FunApp("Paste",[]),[],[[new Terminal("in")],[new Terminal("Klistra")]]), new Rule(27, new FunApp("Redo",[]),[],[[],[new Terminal("Upprepa")]]), new Rule(27, new FunApp("Refine",[]),[],[[],[new Terminal("Raffinera")]]), new Rule(27, new FunApp("Replace",[]),[],[[],[new Terminal("Ersätt")]]), new Rule(27, new FunApp("Select",[]),[],[[],[new Terminal("Välj")]]), new Rule(27, new FunApp("Show",[]),[],[[],[new Terminal("Visa")]]), new Rule(27, new FunApp("Undo",[]),[],[[],[new Terminal("Ångra")]]), new Rule(27, new FunApp("Wrap",[]),[],[[],[new Terminal("Förpacka")]]), new Rule(24, new FunApp("Wrapper",[]),[],[[new Terminal("förpackning")]]), new Rule(23, new FunApp("Wrapper",[]),[],[[new Terminal("förpacknings")]]), new Rule(22, new FunApp("Wrapper",[]),[],[[new Terminal("förpackningen")]]), new Rule(21, new FunApp("Wrapper",[]),[],[[new Terminal("förpackningens")]]), new Rule(20, new FunApp("Wrapper",[]),[],[[new Terminal("förpackningar")]]), new Rule(19, new FunApp("Wrapper",[]),[],[[new Terminal("förpackningars")]]), new Rule(18, new FunApp("Wrapper",[]),[],[[new Terminal("förpackningarna")]]), new Rule(17, new FunApp("Wrapper",[]),[],[[new Terminal("förpackningarnas")]]), new Rule(65, new FunApp("Wrap",[]),[],[[new Terminal("Förpackar")]]), new Rule(64, new FunApp("Wrap",[]),[],[[new Terminal("Förpackas")]]), new Rule(63, new FunApp("Wrap",[]),[],[[new Terminal("Förpacka")]]), new Rule(62, new FunApp("Wrap",[]),[],[[new Terminal("Förpackas")]]), new Rule(61, new FunApp("Wrap",[]),[],[[new Terminal("Förpacka")]]), new Rule(60, new FunApp("Wrap",[]),[],[[new Terminal("Förpackas")]]), new Rule(59, new FunApp("Wrap",[]),[],[[new Terminal("Förpackad")]]), new Rule(58, new FunApp("Wrap",[]),[],[[new Terminal("Förpackads")]]), new Rule(57, new FunApp("Wrap",[]),[],[[new Terminal("Förpackat")]]), new Rule(56, new FunApp("Wrap",[]),[],[[new Terminal("Förpackats")]]), new Rule(55, new FunApp("Wrap",[]),[],[[new Terminal("Förpackade")]]), new Rule(54, new FunApp("Wrap",[]),[],[[new Terminal("Förpackades")]]), new Rule(53, new FunApp("Wrap",[]),[],[[new Terminal("Förpackade")]]), new Rule(52, new FunApp("Wrap",[]),[],[[new Terminal("Förpackades")]]), new Rule(51, new FunApp("Wrap",[]),[],[[new Terminal("Förpackade")]]), new Rule(50, new FunApp("Wrap",[]),[],[[new Terminal("Förpackades")]]), new Rule(49, new FunApp("Wrap",[]),[],[[]]), new Rule(65, new FunApp("Undo",[]),[],[[new Terminal("Ångrar")]]), new Rule(64, new FunApp("Undo",[]),[],[[new Terminal("Ångras")]]), new Rule(63, new FunApp("Undo",[]),[],[[new Terminal("Ångra")]]), new Rule(62, new FunApp("Undo",[]),[],[[new Terminal("Ångras")]]), new Rule(61, new FunApp("Undo",[]),[],[[new Terminal("Ångra")]]), new Rule(60, new FunApp("Undo",[]),[],[[new Terminal("Ångras")]]), new Rule(59, new FunApp("Undo",[]),[],[[new Terminal("Ångrad")]]), new Rule(58, new FunApp("Undo",[]),[],[[new Terminal("Ångrads")]]), new Rule(57, new FunApp("Undo",[]),[],[[new Terminal("Ångrat")]]), new Rule(56, new FunApp("Undo",[]),[],[[new Terminal("Ångrats")]]), new Rule(55, new FunApp("Undo",[]),[],[[new Terminal("Ångrade")]]), new Rule(54, new FunApp("Undo",[]),[],[[new Terminal("Ångrades")]]), new Rule(53, new FunApp("Undo",[]),[],[[new Terminal("Ångrade")]]), new Rule(52, new FunApp("Undo",[]),[],[[new Terminal("Ångrades")]]), new Rule(51, new FunApp("Undo",[]),[],[[new Terminal("Ångrade")]]), new Rule(50, new FunApp("Undo",[]),[],[[new Terminal("Ångrades")]]), new Rule(49, new FunApp("Undo",[]),[],[[]]), new Rule(30, new FunApp("Tree",[]),[],[[new Terminal("träd")]]), new Rule(83, new FunApp("Tree",[]),[],[[new Terminal("träds")]]), new Rule(33, new FunApp("Tree",[]),[],[[new Terminal("trädet")]]), new Rule(82, new FunApp("Tree",[]),[],[[new Terminal("trädets")]]), new Rule(81, new FunApp("Tree",[]),[],[[new Terminal("träd")]]), new Rule(80, new FunApp("Tree",[]),[],[[new Terminal("träds")]]), new Rule(79, new FunApp("Tree",[]),[],[[new Terminal("träden")]]), new Rule(78, new FunApp("Tree",[]),[],[[new Terminal("trädens")]]), new Rule(24, new FunApp("Swedish",[]),[],[[new Terminal("Svenska")]]), new Rule(23, new FunApp("Swedish",[]),[],[[new Terminal("Svenskas")]]), new Rule(22, new FunApp("Swedish",[]),[],[[new Terminal("Svenskan")]]), new Rule(21, new FunApp("Swedish",[]),[],[[new Terminal("Svenskans")]]), new Rule(20, new FunApp("Swedish",[]),[],[[new Terminal("Svenskor")]]), new Rule(19, new FunApp("Swedish",[]),[],[[new Terminal("Svenskors")]]), new Rule(18, new FunApp("Swedish",[]),[],[[new Terminal("Svenskorna")]]), new Rule(17, new FunApp("Swedish",[]),[],[[new Terminal("Svenskornas")]]), new Rule(24, new FunApp("String_N",[]),[],[[new Terminal("sträng")]]), new Rule(23, new FunApp("String_N",[]),[],[[new Terminal("strängs")]]), new Rule(22, new FunApp("String_N",[]),[],[[new Terminal("strängen")]]), new Rule(21, new FunApp("String_N",[]),[],[[new Terminal("strängens")]]), new Rule(20, new FunApp("String_N",[]),[],[[new Terminal("strängar")]]), new Rule(19, new FunApp("String_N",[]),[],[[new Terminal("strängars")]]), new Rule(18, new FunApp("String_N",[]),[],[[new Terminal("strängarna")]]), new Rule(17, new FunApp("String_N",[]),[],[[new Terminal("strängarnas")]]), new Rule(24, new FunApp("Spanish",[]),[],[[new Terminal("Spanska")]]), new Rule(23, new FunApp("Spanish",[]),[],[[new Terminal("Spanskas")]]), new Rule(22, new FunApp("Spanish",[]),[],[[new Terminal("Spanskan")]]), new Rule(21, new FunApp("Spanish",[]),[],[[new Terminal("Spanskans")]]), new Rule(20, new FunApp("Spanish",[]),[],[[new Terminal("Spanskor")]]), new Rule(19, new FunApp("Spanish",[]),[],[[new Terminal("Spanskors")]]), new Rule(18, new FunApp("Spanish",[]),[],[[new Terminal("Spanskorna")]]), new Rule(17, new FunApp("Spanish",[]),[],[[new Terminal("Spanskornas")]]), new Rule(25, new FunApp("SingleWordCommand",[new Arg(0)]),[36],[[new ArgProj(0, 1), new ArgProj(0, 0), new Terminal("dig")]]), new Rule(25, new FunApp("SingleWordCommand",[new Arg(0)]),[35],[[new ArgProj(0, 1), new ArgProj(0, 0)]]), new Rule(25, new FunApp("SingleWordCommand",[new Arg(0)]),[27],[[new ArgProj(0, 1), new ArgProj(0, 0)]]), new Rule(65, new FunApp("Show",[]),[],[[new Terminal("Visar")]]), new Rule(64, new FunApp("Show",[]),[],[[new Terminal("Visas")]]), new Rule(63, new FunApp("Show",[]),[],[[new Terminal("Visa")]]), new Rule(62, new FunApp("Show",[]),[],[[new Terminal("Visas")]]), new Rule(61, new FunApp("Show",[]),[],[[new Terminal("Visa")]]), new Rule(60, new FunApp("Show",[]),[],[[new Terminal("Visas")]]), new Rule(59, new FunApp("Show",[]),[],[[new Terminal("Visad")]]), new Rule(58, new FunApp("Show",[]),[],[[new Terminal("Visads")]]), new Rule(57, new FunApp("Show",[]),[],[[new Terminal("Visat")]]), new Rule(56, new FunApp("Show",[]),[],[[new Terminal("Visats")]]), new Rule(55, new FunApp("Show",[]),[],[[new Terminal("Visade")]]), new Rule(54, new FunApp("Show",[]),[],[[new Terminal("Visades")]]), new Rule(53, new FunApp("Show",[]),[],[[new Terminal("Visade")]]), new Rule(52, new FunApp("Show",[]),[],[[new Terminal("Visades")]]), new Rule(51, new FunApp("Show",[]),[],[[new Terminal("Visade")]]), new Rule(50, new FunApp("Show",[]),[],[[new Terminal("Visades")]]), new Rule(49, new FunApp("Show",[]),[],[[]]), new Rule(65, new FunApp("Select",[]),[],[[new Terminal("Väljer")]]), new Rule(64, new FunApp("Select",[]),[],[[new Terminal("Väljs")]]), new Rule(63, new FunApp("Select",[]),[],[[new Terminal("Välj")]]), new Rule(62, new FunApp("Select",[]),[],[[new Terminal("Väljs")]]), new Rule(61, new FunApp("Select",[]),[],[[new Terminal("Välja")]]), new Rule(60, new FunApp("Select",[]),[],[[new Terminal("Väljas")]]), new Rule(59, new FunApp("Select",[]),[],[[new Terminal("Väljt")]]), new Rule(58, new FunApp("Select",[]),[],[[new Terminal("Väljts")]]), new Rule(57, new FunApp("Select",[]),[],[[new Terminal("Väljt")]]), new Rule(56, new FunApp("Select",[]),[],[[new Terminal("Väljts")]]), new Rule(55, new FunApp("Select",[]),[],[[new Terminal("Väljta")]]), new Rule(54, new FunApp("Select",[]),[],[[new Terminal("Väljtas")]]), new Rule(53, new FunApp("Select",[]),[],[[new Terminal("Väljta")]]), new Rule(52, new FunApp("Select",[]),[],[[new Terminal("Väljtas")]]), new Rule(51, new FunApp("Select",[]),[],[[new Terminal("Väljta")]]), new Rule(50, new FunApp("Select",[]),[],[[new Terminal("Väljtas")]]), new Rule(49, new FunApp("Select",[]),[],[[]]), new Rule(24, new FunApp("Russian",[]),[],[[new Terminal("Ryska")]]), new Rule(23, new FunApp("Russian",[]),[],[[new Terminal("Ryskas")]]), new Rule(22, new FunApp("Russian",[]),[],[[new Terminal("Ryskan")]]), new Rule(21, new FunApp("Russian",[]),[],[[new Terminal("Ryskans")]]), new Rule(20, new FunApp("Russian",[]),[],[[new Terminal("Ryskor")]]), new Rule(19, new FunApp("Russian",[]),[],[[new Terminal("Ryskors")]]), new Rule(18, new FunApp("Russian",[]),[],[[new Terminal("Ryskorna")]]), new Rule(17, new FunApp("Russian",[]),[],[[new Terminal("Ryskornas")]]), new Rule(65, new FunApp("Replace",[]),[],[[new Terminal("Ersätter")]]), new Rule(64, new FunApp("Replace",[]),[],[[new Terminal("Ersätts")]]), new Rule(63, new FunApp("Replace",[]),[],[[new Terminal("Ersätt")]]), new Rule(62, new FunApp("Replace",[]),[],[[new Terminal("Ersätts")]]), new Rule(61, new FunApp("Replace",[]),[],[[new Terminal("Ersätta")]]), new Rule(60, new FunApp("Replace",[]),[],[[new Terminal("Ersättas")]]), new Rule(59, new FunApp("Replace",[]),[],[[new Terminal("Ersättt")]]), new Rule(58, new FunApp("Replace",[]),[],[[new Terminal("Ersättts")]]), new Rule(57, new FunApp("Replace",[]),[],[[new Terminal("Ersättt")]]), new Rule(56, new FunApp("Replace",[]),[],[[new Terminal("Ersättts")]]), new Rule(55, new FunApp("Replace",[]),[],[[new Terminal("Ersättta")]]), new Rule(54, new FunApp("Replace",[]),[],[[new Terminal("Ersätttas")]]), new Rule(53, new FunApp("Replace",[]),[],[[new Terminal("Ersättta")]]), new Rule(52, new FunApp("Replace",[]),[],[[new Terminal("Ersätttas")]]), new Rule(51, new FunApp("Replace",[]),[],[[new Terminal("Ersättta")]]), new Rule(50, new FunApp("Replace",[]),[],[[new Terminal("Ersätttas")]]), new Rule(49, new FunApp("Replace",[]),[],[[]]), new Rule(24, new FunApp("Refinement",[]),[],[[new Terminal("raffinemang")]]), new Rule(23, new FunApp("Refinement",[]),[],[[new Terminal("raffinemangs")]]), new Rule(22, new FunApp("Refinement",[]),[],[[new Terminal("raffinemangen")]]), new Rule(21, new FunApp("Refinement",[]),[],[[new Terminal("raffinemangens")]]), new Rule(20, new FunApp("Refinement",[]),[],[[new Terminal("raffinemangar")]]), new Rule(19, new FunApp("Refinement",[]),[],[[new Terminal("raffinemangars")]]), new Rule(18, new FunApp("Refinement",[]),[],[[new Terminal("raffinemangarna")]]), new Rule(17, new FunApp("Refinement",[]),[],[[new Terminal("raffinemangarnas")]]), new Rule(65, new FunApp("Refine",[]),[],[[new Terminal("Raffinerar")]]), new Rule(64, new FunApp("Refine",[]),[],[[new Terminal("Raffineras")]]), new Rule(63, new FunApp("Refine",[]),[],[[new Terminal("Raffinera")]]), new Rule(62, new FunApp("Refine",[]),[],[[new Terminal("Raffineras")]]), new Rule(61, new FunApp("Refine",[]),[],[[new Terminal("Raffinera")]]), new Rule(60, new FunApp("Refine",[]),[],[[new Terminal("Raffineras")]]), new Rule(59, new FunApp("Refine",[]),[],[[new Terminal("Raffinerad")]]), new Rule(58, new FunApp("Refine",[]),[],[[new Terminal("Raffinerads")]]), new Rule(57, new FunApp("Refine",[]),[],[[new Terminal("Raffinerat")]]), new Rule(56, new FunApp("Refine",[]),[],[[new Terminal("Raffinerats")]]), new Rule(55, new FunApp("Refine",[]),[],[[new Terminal("Raffinerade")]]), new Rule(54, new FunApp("Refine",[]),[],[[new Terminal("Raffinerades")]]), new Rule(53, new FunApp("Refine",[]),[],[[new Terminal("Raffinerade")]]), new Rule(52, new FunApp("Refine",[]),[],[[new Terminal("Raffinerades")]]), new Rule(51, new FunApp("Refine",[]),[],[[new Terminal("Raffinerade")]]), new Rule(50, new FunApp("Refine",[]),[],[[new Terminal("Raffinerades")]]), new Rule(49, new FunApp("Refine",[]),[],[[]]), new Rule(65, new FunApp("Redo",[]),[],[[new Terminal("Upprepar")]]), new Rule(64, new FunApp("Redo",[]),[],[[new Terminal("Upprepas")]]), new Rule(63, new FunApp("Redo",[]),[],[[new Terminal("Upprepa")]]), new Rule(62, new FunApp("Redo",[]),[],[[new Terminal("Upprepas")]]), new Rule(61, new FunApp("Redo",[]),[],[[new Terminal("Upprepa")]]), new Rule(60, new FunApp("Redo",[]),[],[[new Terminal("Upprepas")]]), new Rule(59, new FunApp("Redo",[]),[],[[new Terminal("Upprepad")]]), new Rule(58, new FunApp("Redo",[]),[],[[new Terminal("Upprepads")]]), new Rule(57, new FunApp("Redo",[]),[],[[new Terminal("Upprepat")]]), new Rule(56, new FunApp("Redo",[]),[],[[new Terminal("Upprepats")]]), new Rule(55, new FunApp("Redo",[]),[],[[new Terminal("Upprepade")]]), new Rule(54, new FunApp("Redo",[]),[],[[new Terminal("Upprepades")]]), new Rule(53, new FunApp("Redo",[]),[],[[new Terminal("Upprepade")]]), new Rule(52, new FunApp("Redo",[]),[],[[new Terminal("Upprepades")]]), new Rule(51, new FunApp("Redo",[]),[],[[new Terminal("Upprepade")]]), new Rule(50, new FunApp("Redo",[]),[],[[new Terminal("Upprepades")]]), new Rule(49, new FunApp("Redo",[]),[],[[]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[36, 34, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig"), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[36, 32, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig"), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[36, 31, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig"), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[36, 29, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig"), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[36, 28, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig"), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[36, 26, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig"), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[35, 34, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[35, 32, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[35, 31, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[35, 29, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[35, 28, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[35, 26, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[27, 34, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[27, 32, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[27, 31, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[27, 29, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[27, 28, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(25, new FunApp("RandomlyCommand",[new Arg(0), new Arg(1), new Arg(2)]),[27, 26, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("slumpmässigt")]]), new Rule(16, new FunApp("Previous",[]),[],[[new Terminal("föregående")]]), new Rule(15, new FunApp("Previous",[]),[],[[new Terminal("föregåendes")]]), new Rule(14, new FunApp("Previous",[]),[],[[new Terminal("föregående")]]), new Rule(13, new FunApp("Previous",[]),[],[[new Terminal("föregåendes")]]), new Rule(12, new FunApp("Previous",[]),[],[[new Terminal("föregående")]]), new Rule(11, new FunApp("Previous",[]),[],[[new Terminal("föregåendes")]]), new Rule(10, new FunApp("Previous",[]),[],[[new Terminal("föregående")]]), new Rule(9, new FunApp("Previous",[]),[],[[new Terminal("föregåendes")]]), new Rule(8, new FunApp("Previous",[]),[],[[new Terminal("föregående")]]), new Rule(7, new FunApp("Previous",[]),[],[[new Terminal("föregåendes")]]), new Rule(6, new FunApp("Previous",[]),[],[[]]), new Rule(5, new FunApp("Previous",[]),[],[[new Terminal("s")]]), new Rule(4, new FunApp("Previous",[]),[],[[]]), new Rule(3, new FunApp("Previous",[]),[],[[new Terminal("s")]]), new Rule(2, new FunApp("Previous",[]),[],[[new Terminal("a")]]), new Rule(1, new FunApp("Previous",[]),[],[[new Terminal("as")]]), new Rule(65, new FunApp("Paste",[]),[],[[new Terminal("Klistrar")]]), new Rule(64, new FunApp("Paste",[]),[],[[new Terminal("Klistras")]]), new Rule(63, new FunApp("Paste",[]),[],[[new Terminal("Klistra")]]), new Rule(62, new FunApp("Paste",[]),[],[[new Terminal("Klistras")]]), new Rule(61, new FunApp("Paste",[]),[],[[new Terminal("Klistra")]]), new Rule(60, new FunApp("Paste",[]),[],[[new Terminal("Klistras")]]), new Rule(59, new FunApp("Paste",[]),[],[[new Terminal("Klistrad")]]), new Rule(58, new FunApp("Paste",[]),[],[[new Terminal("Klistrads")]]), new Rule(57, new FunApp("Paste",[]),[],[[new Terminal("Klistrat")]]), new Rule(56, new FunApp("Paste",[]),[],[[new Terminal("Klistrats")]]), new Rule(55, new FunApp("Paste",[]),[],[[new Terminal("Klistrade")]]), new Rule(54, new FunApp("Paste",[]),[],[[new Terminal("Klistrades")]]), new Rule(53, new FunApp("Paste",[]),[],[[new Terminal("Klistrade")]]), new Rule(52, new FunApp("Paste",[]),[],[[new Terminal("Klistrades")]]), new Rule(51, new FunApp("Paste",[]),[],[[new Terminal("Klistrade")]]), new Rule(50, new FunApp("Paste",[]),[],[[new Terminal("Klistrades")]]), new Rule(49, new FunApp("Paste",[]),[],[[new Terminal("in")]]), new Rule(65, new FunApp("Parse",[]),[],[[new Terminal("Parsar")]]), new Rule(64, new FunApp("Parse",[]),[],[[new Terminal("Parsas")]]), new Rule(63, new FunApp("Parse",[]),[],[[new Terminal("Parsa")]]), new Rule(62, new FunApp("Parse",[]),[],[[new Terminal("Parsas")]]), new Rule(61, new FunApp("Parse",[]),[],[[new Terminal("Parsa")]]), new Rule(60, new FunApp("Parse",[]),[],[[new Terminal("Parsas")]]), new Rule(59, new FunApp("Parse",[]),[],[[new Terminal("Parsad")]]), new Rule(58, new FunApp("Parse",[]),[],[[new Terminal("Parsads")]]), new Rule(57, new FunApp("Parse",[]),[],[[new Terminal("Parsat")]]), new Rule(56, new FunApp("Parse",[]),[],[[new Terminal("Parsats")]]), new Rule(55, new FunApp("Parse",[]),[],[[new Terminal("Parsade")]]), new Rule(54, new FunApp("Parse",[]),[],[[new Terminal("Parsades")]]), new Rule(53, new FunApp("Parse",[]),[],[[new Terminal("Parsade")]]), new Rule(52, new FunApp("Parse",[]),[],[[new Terminal("Parsades")]]), new Rule(51, new FunApp("Parse",[]),[],[[new Terminal("Parsade")]]), new Rule(50, new FunApp("Parse",[]),[],[[new Terminal("Parsades")]]), new Rule(49, new FunApp("Parse",[]),[],[[]]), new Rule(24, new FunApp("Page",[]),[],[[new Terminal("sida")]]), new Rule(23, new FunApp("Page",[]),[],[[new Terminal("sidas")]]), new Rule(22, new FunApp("Page",[]),[],[[new Terminal("sidan")]]), new Rule(21, new FunApp("Page",[]),[],[[new Terminal("sidans")]]), new Rule(20, new FunApp("Page",[]),[],[[new Terminal("sidor")]]), new Rule(19, new FunApp("Page",[]),[],[[new Terminal("sidors")]]), new Rule(18, new FunApp("Page",[]),[],[[new Terminal("sidorna")]]), new Rule(17, new FunApp("Page",[]),[],[[new Terminal("sidornas")]]), new Rule(24, new FunApp("Norwegian",[]),[],[[new Terminal("Norska")]]), new Rule(23, new FunApp("Norwegian",[]),[],[[new Terminal("Norskas")]]), new Rule(22, new FunApp("Norwegian",[]),[],[[new Terminal("Norskan")]]), new Rule(21, new FunApp("Norwegian",[]),[],[[new Terminal("Norskans")]]), new Rule(20, new FunApp("Norwegian",[]),[],[[new Terminal("Norskor")]]), new Rule(19, new FunApp("Norwegian",[]),[],[[new Terminal("Norskors")]]), new Rule(18, new FunApp("Norwegian",[]),[],[[new Terminal("Norskorna")]]), new Rule(17, new FunApp("Norwegian",[]),[],[[new Terminal("Norskornas")]]), new Rule(24, new FunApp("Node",[]),[],[[new Terminal("nod")]]), new Rule(23, new FunApp("Node",[]),[],[[new Terminal("nods")]]), new Rule(22, new FunApp("Node",[]),[],[[new Terminal("noden")]]), new Rule(21, new FunApp("Node",[]),[],[[new Terminal("nodens")]]), new Rule(20, new FunApp("Node",[]),[],[[new Terminal("nodar")]]), new Rule(19, new FunApp("Node",[]),[],[[new Terminal("nodars")]]), new Rule(18, new FunApp("Node",[]),[],[[new Terminal("nodarna")]]), new Rule(17, new FunApp("Node",[]),[],[[new Terminal("nodarnas")]]), new Rule(16, new FunApp("Next",[]),[],[[new Terminal("näst")]]), new Rule(15, new FunApp("Next",[]),[],[[new Terminal("nästs")]]), new Rule(14, new FunApp("Next",[]),[],[[new Terminal("nästt")]]), new Rule(13, new FunApp("Next",[]),[],[[new Terminal("nästts")]]), new Rule(12, new FunApp("Next",[]),[],[[new Terminal("nästa")]]), new Rule(11, new FunApp("Next",[]),[],[[new Terminal("nästas")]]), new Rule(10, new FunApp("Next",[]),[],[[new Terminal("nästa")]]), new Rule(9, new FunApp("Next",[]),[],[[new Terminal("nästas")]]), new Rule(8, new FunApp("Next",[]),[],[[new Terminal("nästa")]]), new Rule(7, new FunApp("Next",[]),[],[[new Terminal("nästas")]]), new Rule(6, new FunApp("Next",[]),[],[[new Terminal("nästare")]]), new Rule(5, new FunApp("Next",[]),[],[[new Terminal("nästares")]]), new Rule(4, new FunApp("Next",[]),[],[[new Terminal("nästast")]]), new Rule(3, new FunApp("Next",[]),[],[[new Terminal("nästasts")]]), new Rule(2, new FunApp("Next",[]),[],[[new Terminal("nästaste")]]), new Rule(1, new FunApp("Next",[]),[],[[new Terminal("nästastes")]]), new Rule(30, new FunApp("Language",[]),[],[[new Terminal("språk")]]), new Rule(83, new FunApp("Language",[]),[],[[new Terminal("språks")]]), new Rule(33, new FunApp("Language",[]),[],[[new Terminal("språket")]]), new Rule(82, new FunApp("Language",[]),[],[[new Terminal("språkets")]]), new Rule(81, new FunApp("Language",[]),[],[[new Terminal("språk")]]), new Rule(80, new FunApp("Language",[]),[],[[new Terminal("språks")]]), new Rule(79, new FunApp("Language",[]),[],[[new Terminal("språken")]]), new Rule(78, new FunApp("Language",[]),[],[[new Terminal("språkens")]]), new Rule(25, new FunApp("Label",[new Arg(0)]),[96],[[new ArgProj(0, 0)]]), new Rule(96, new Arg(0),[30],[[new ArgProj(0, 0)]]), new Rule(96, new Arg(0),[24],[[new ArgProj(0, 0)]]), new Rule(24, new FunApp("Italian",[]),[],[[new Terminal("Italienska")]]), new Rule(23, new FunApp("Italian",[]),[],[[new Terminal("Italienskas")]]), new Rule(22, new FunApp("Italian",[]),[],[[new Terminal("Italienskan")]]), new Rule(21, new FunApp("Italian",[]),[],[[new Terminal("Italienskans")]]), new Rule(20, new FunApp("Italian",[]),[],[[new Terminal("Italienskor")]]), new Rule(19, new FunApp("Italian",[]),[],[[new Terminal("Italienskors")]]), new Rule(18, new FunApp("Italian",[]),[],[[new Terminal("Italienskorna")]]), new Rule(17, new FunApp("Italian",[]),[],[[new Terminal("Italienskornas")]]), new Rule(30, new FunApp("Integer_N",[]),[],[[new Terminal("heltal")]]), new Rule(83, new FunApp("Integer_N",[]),[],[[new Terminal("heltals")]]), new Rule(33, new FunApp("Integer_N",[]),[],[[new Terminal("heltalet")]]), new Rule(82, new FunApp("Integer_N",[]),[],[[new Terminal("heltalets")]]), new Rule(81, new FunApp("Integer_N",[]),[],[[new Terminal("heltal")]]), new Rule(80, new FunApp("Integer_N",[]),[],[[new Terminal("heltals")]]), new Rule(79, new FunApp("Integer_N",[]),[],[[new Terminal("heltalen")]]), new Rule(78, new FunApp("Integer_N",[]),[],[[new Terminal("heltalens")]]), new Rule(95, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(94, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(39, new FunApp("IndefSgDet",[]),[],[[new Terminal("en")]]), new Rule(46, new FunApp("IndefSgDet",[]),[],[[new Terminal("ett")]]), new Rule(93, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(92, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(26, new FunApp("IndefSgDet",[]),[],[[new Terminal("en")]]), new Rule(31, new FunApp("IndefSgDet",[]),[],[[new Terminal("ett")]]), new Rule(91, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(90, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(89, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(88, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(87, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(86, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(85, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(84, new FunApp("IndefSgDet",[]),[],[[]]), new Rule(95, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(94, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(39, new FunApp("IndefPlDet",[]),[],[[new Terminal("en")]]), new Rule(46, new FunApp("IndefPlDet",[]),[],[[new Terminal("ett")]]), new Rule(93, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(92, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(26, new FunApp("IndefPlDet",[]),[],[[new Terminal("en")]]), new Rule(31, new FunApp("IndefPlDet",[]),[],[[new Terminal("ett")]]), new Rule(91, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(90, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(89, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(88, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(87, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(86, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(85, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(84, new FunApp("IndefPlDet",[]),[],[[]]), new Rule(24, new FunApp("German",[]),[],[[new Terminal("Tyska")]]), new Rule(23, new FunApp("German",[]),[],[[new Terminal("Tyskas")]]), new Rule(22, new FunApp("German",[]),[],[[new Terminal("Tyskan")]]), new Rule(21, new FunApp("German",[]),[],[[new Terminal("Tyskans")]]), new Rule(20, new FunApp("German",[]),[],[[new Terminal("Tyskor")]]), new Rule(19, new FunApp("German",[]),[],[[new Terminal("Tyskors")]]), new Rule(18, new FunApp("German",[]),[],[[new Terminal("Tyskorna")]]), new Rule(17, new FunApp("German",[]),[],[[new Terminal("Tyskornas")]]), new Rule(24, new FunApp("French",[]),[],[[new Terminal("Franska")]]), new Rule(23, new FunApp("French",[]),[],[[new Terminal("Franskas")]]), new Rule(22, new FunApp("French",[]),[],[[new Terminal("Franskan")]]), new Rule(21, new FunApp("French",[]),[],[[new Terminal("Franskans")]]), new Rule(20, new FunApp("French",[]),[],[[new Terminal("Franskor")]]), new Rule(19, new FunApp("French",[]),[],[[new Terminal("Franskors")]]), new Rule(18, new FunApp("French",[]),[],[[new Terminal("Franskorna")]]), new Rule(17, new FunApp("French",[]),[],[[new Terminal("Franskornas")]]), new Rule(30, new FunApp("Float_N",[]),[],[[new Terminal("flyttal")]]), new Rule(83, new FunApp("Float_N",[]),[],[[new Terminal("flyttals")]]), new Rule(33, new FunApp("Float_N",[]),[],[[new Terminal("flyttalet")]]), new Rule(82, new FunApp("Float_N",[]),[],[[new Terminal("flyttalets")]]), new Rule(81, new FunApp("Float_N",[]),[],[[new Terminal("flyttal")]]), new Rule(80, new FunApp("Float_N",[]),[],[[new Terminal("flyttals")]]), new Rule(79, new FunApp("Float_N",[]),[],[[new Terminal("flyttalen")]]), new Rule(78, new FunApp("Float_N",[]),[],[[new Terminal("flyttalens")]]), new Rule(24, new FunApp("Finnish",[]),[],[[new Terminal("Finska")]]), new Rule(23, new FunApp("Finnish",[]),[],[[new Terminal("Finskas")]]), new Rule(22, new FunApp("Finnish",[]),[],[[new Terminal("Finskan")]]), new Rule(21, new FunApp("Finnish",[]),[],[[new Terminal("Finskans")]]), new Rule(20, new FunApp("Finnish",[]),[],[[new Terminal("Finskor")]]), new Rule(19, new FunApp("Finnish",[]),[],[[new Terminal("Finskors")]]), new Rule(18, new FunApp("Finnish",[]),[],[[new Terminal("Finskorna")]]), new Rule(17, new FunApp("Finnish",[]),[],[[new Terminal("Finskornas")]]), new Rule(25, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[44, 30],[[new Terminal("det"), new Terminal("finns"), new Terminal("inte"), new Terminal("ett"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(25, new FunApp("ErrorMessage",[new Arg(0), new Arg(1)]),[37, 24],[[new Terminal("det"), new Terminal("finns"), new Terminal("inte"), new Terminal("en"), new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(65, new FunApp("Enter",[]),[],[[new Terminal("Skriver")]]), new Rule(64, new FunApp("Enter",[]),[],[[new Terminal("Skrivs")]]), new Rule(63, new FunApp("Enter",[]),[],[[new Terminal("Skriv")]]), new Rule(62, new FunApp("Enter",[]),[],[[new Terminal("Skrivs")]]), new Rule(61, new FunApp("Enter",[]),[],[[new Terminal("Skriva")]]), new Rule(60, new FunApp("Enter",[]),[],[[new Terminal("Skrivas")]]), new Rule(59, new FunApp("Enter",[]),[],[[new Terminal("Skrivd")]]), new Rule(58, new FunApp("Enter",[]),[],[[new Terminal("Skrivds")]]), new Rule(57, new FunApp("Enter",[]),[],[[new Terminal("Skrivt")]]), new Rule(56, new FunApp("Enter",[]),[],[[new Terminal("Skrivts")]]), new Rule(55, new FunApp("Enter",[]),[],[[new Terminal("Skrivda")]]), new Rule(54, new FunApp("Enter",[]),[],[[new Terminal("Skrivdas")]]), new Rule(53, new FunApp("Enter",[]),[],[[new Terminal("Skrivda")]]), new Rule(52, new FunApp("Enter",[]),[],[[new Terminal("Skrivdas")]]), new Rule(51, new FunApp("Enter",[]),[],[[new Terminal("Skrivda")]]), new Rule(50, new FunApp("Enter",[]),[],[[new Terminal("Skrivdas")]]), new Rule(49, new FunApp("Enter",[]),[],[[]]), new Rule(24, new FunApp("English",[]),[],[[new Terminal("Engelska")]]), new Rule(23, new FunApp("English",[]),[],[[new Terminal("Engelskas")]]), new Rule(22, new FunApp("English",[]),[],[[new Terminal("Engelskan")]]), new Rule(21, new FunApp("English",[]),[],[[new Terminal("Engelskans")]]), new Rule(20, new FunApp("English",[]),[],[[new Terminal("Engelskor")]]), new Rule(19, new FunApp("English",[]),[],[[new Terminal("Engelskors")]]), new Rule(18, new FunApp("English",[]),[],[[new Terminal("Engelskorna")]]), new Rule(17, new FunApp("English",[]),[],[[new Terminal("Engelskornas")]]), new Rule(65, new FunApp("Delete",[]),[],[[new Terminal("Raderar")]]), new Rule(64, new FunApp("Delete",[]),[],[[new Terminal("Raderas")]]), new Rule(63, new FunApp("Delete",[]),[],[[new Terminal("Radera")]]), new Rule(62, new FunApp("Delete",[]),[],[[new Terminal("Raderas")]]), new Rule(61, new FunApp("Delete",[]),[],[[new Terminal("Radera")]]), new Rule(60, new FunApp("Delete",[]),[],[[new Terminal("Raderas")]]), new Rule(59, new FunApp("Delete",[]),[],[[new Terminal("Raderad")]]), new Rule(58, new FunApp("Delete",[]),[],[[new Terminal("Raderads")]]), new Rule(57, new FunApp("Delete",[]),[],[[new Terminal("Raderat")]]), new Rule(56, new FunApp("Delete",[]),[],[[new Terminal("Raderats")]]), new Rule(55, new FunApp("Delete",[]),[],[[new Terminal("Raderade")]]), new Rule(54, new FunApp("Delete",[]),[],[[new Terminal("Raderades")]]), new Rule(53, new FunApp("Delete",[]),[],[[new Terminal("Raderade")]]), new Rule(52, new FunApp("Delete",[]),[],[[new Terminal("Raderades")]]), new Rule(51, new FunApp("Delete",[]),[],[[new Terminal("Raderade")]]), new Rule(50, new FunApp("Delete",[]),[],[[new Terminal("Raderades")]]), new Rule(49, new FunApp("Delete",[]),[],[[]]), new Rule(77, new FunApp("DefSgDet",[]),[],[[new Terminal("den")]]), new Rule(76, new FunApp("DefSgDet",[]),[],[[new Terminal("det")]]), new Rule(43, new FunApp("DefSgDet",[]),[],[[new Terminal("den")]]), new Rule(48, new FunApp("DefSgDet",[]),[],[[new Terminal("det")]]), new Rule(75, new FunApp("DefSgDet",[]),[],[[new Terminal("den")]]), new Rule(74, new FunApp("DefSgDet",[]),[],[[new Terminal("det")]]), new Rule(29, new FunApp("DefSgDet",[]),[],[[]]), new Rule(34, new FunApp("DefSgDet",[]),[],[[]]), new Rule(73, new FunApp("DefSgDet",[]),[],[[new Terminal("de")]]), new Rule(72, new FunApp("DefSgDet",[]),[],[[new Terminal("de")]]), new Rule(71, new FunApp("DefSgDet",[]),[],[[new Terminal("de")]]), new Rule(70, new FunApp("DefSgDet",[]),[],[[new Terminal("de")]]), new Rule(69, new FunApp("DefSgDet",[]),[],[[new Terminal("de")]]), new Rule(68, new FunApp("DefSgDet",[]),[],[[new Terminal("de")]]), new Rule(67, new FunApp("DefSgDet",[]),[],[[]]), new Rule(66, new FunApp("DefSgDet",[]),[],[[]]), new Rule(77, new FunApp("DefPlDet",[]),[],[[new Terminal("den")]]), new Rule(76, new FunApp("DefPlDet",[]),[],[[new Terminal("det")]]), new Rule(43, new FunApp("DefPlDet",[]),[],[[new Terminal("den")]]), new Rule(48, new FunApp("DefPlDet",[]),[],[[new Terminal("det")]]), new Rule(75, new FunApp("DefPlDet",[]),[],[[new Terminal("den")]]), new Rule(74, new FunApp("DefPlDet",[]),[],[[new Terminal("det")]]), new Rule(29, new FunApp("DefPlDet",[]),[],[[]]), new Rule(34, new FunApp("DefPlDet",[]),[],[[]]), new Rule(73, new FunApp("DefPlDet",[]),[],[[new Terminal("de")]]), new Rule(72, new FunApp("DefPlDet",[]),[],[[new Terminal("de")]]), new Rule(71, new FunApp("DefPlDet",[]),[],[[new Terminal("de")]]), new Rule(70, new FunApp("DefPlDet",[]),[],[[new Terminal("de")]]), new Rule(69, new FunApp("DefPlDet",[]),[],[[new Terminal("de")]]), new Rule(68, new FunApp("DefPlDet",[]),[],[[new Terminal("de")]]), new Rule(67, new FunApp("DefPlDet",[]),[],[[]]), new Rule(66, new FunApp("DefPlDet",[]),[],[[]]), new Rule(24, new FunApp("Danish",[]),[],[[new Terminal("Danska")]]), new Rule(23, new FunApp("Danish",[]),[],[[new Terminal("Danskas")]]), new Rule(22, new FunApp("Danish",[]),[],[[new Terminal("Danskan")]]), new Rule(21, new FunApp("Danish",[]),[],[[new Terminal("Danskans")]]), new Rule(20, new FunApp("Danish",[]),[],[[new Terminal("Danskor")]]), new Rule(19, new FunApp("Danish",[]),[],[[new Terminal("Danskors")]]), new Rule(18, new FunApp("Danish",[]),[],[[new Terminal("Danskorna")]]), new Rule(17, new FunApp("Danish",[]),[],[[new Terminal("Danskornas")]]), new Rule(65, new FunApp("Cut",[]),[],[[new Terminal("Klipper")]]), new Rule(64, new FunApp("Cut",[]),[],[[new Terminal("Klipps")]]), new Rule(63, new FunApp("Cut",[]),[],[[new Terminal("Klipp")]]), new Rule(62, new FunApp("Cut",[]),[],[[new Terminal("Klipps")]]), new Rule(61, new FunApp("Cut",[]),[],[[new Terminal("Klippa")]]), new Rule(60, new FunApp("Cut",[]),[],[[new Terminal("Klippas")]]), new Rule(59, new FunApp("Cut",[]),[],[[new Terminal("Klippt")]]), new Rule(58, new FunApp("Cut",[]),[],[[new Terminal("Klippts")]]), new Rule(57, new FunApp("Cut",[]),[],[[new Terminal("Klippt")]]), new Rule(56, new FunApp("Cut",[]),[],[[new Terminal("Klippts")]]), new Rule(55, new FunApp("Cut",[]),[],[[new Terminal("Klippta")]]), new Rule(54, new FunApp("Cut",[]),[],[[new Terminal("Klipptas")]]), new Rule(53, new FunApp("Cut",[]),[],[[new Terminal("Klippta")]]), new Rule(52, new FunApp("Cut",[]),[],[[new Terminal("Klipptas")]]), new Rule(51, new FunApp("Cut",[]),[],[[new Terminal("Klippta")]]), new Rule(50, new FunApp("Cut",[]),[],[[new Terminal("Klipptas")]]), new Rule(49, new FunApp("Cut",[]),[],[[new Terminal("ut")]]), new Rule(65, new FunApp("Copy",[]),[],[[new Terminal("Kopierar")]]), new Rule(64, new FunApp("Copy",[]),[],[[new Terminal("Kopieras")]]), new Rule(63, new FunApp("Copy",[]),[],[[new Terminal("Kopiera")]]), new Rule(62, new FunApp("Copy",[]),[],[[new Terminal("Kopieras")]]), new Rule(61, new FunApp("Copy",[]),[],[[new Terminal("Kopiera")]]), new Rule(60, new FunApp("Copy",[]),[],[[new Terminal("Kopieras")]]), new Rule(59, new FunApp("Copy",[]),[],[[new Terminal("Kopierad")]]), new Rule(58, new FunApp("Copy",[]),[],[[new Terminal("Kopierads")]]), new Rule(57, new FunApp("Copy",[]),[],[[new Terminal("Kopierat")]]), new Rule(56, new FunApp("Copy",[]),[],[[new Terminal("Kopierats")]]), new Rule(55, new FunApp("Copy",[]),[],[[new Terminal("Kopierade")]]), new Rule(54, new FunApp("Copy",[]),[],[[new Terminal("Kopierades")]]), new Rule(53, new FunApp("Copy",[]),[],[[new Terminal("Kopierade")]]), new Rule(52, new FunApp("Copy",[]),[],[[new Terminal("Kopierades")]]), new Rule(51, new FunApp("Copy",[]),[],[[new Terminal("Kopierade")]]), new Rule(50, new FunApp("Copy",[]),[],[[new Terminal("Kopierades")]]), new Rule(49, new FunApp("Copy",[]),[],[[]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[36, 48, 40, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("dig")]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[36, 47, 40, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("dig")]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[36, 46, 44, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("dig")]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[36, 43, 40, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("dig")]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[36, 42, 40, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("dig")]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[36, 39, 37, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0), new Terminal("dig")]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[35, 48, 40, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[35, 47, 40, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[35, 46, 44, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[35, 43, 40, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[35, 42, 40, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[35, 39, 37, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[27, 48, 40, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[27, 47, 40, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[27, 46, 44, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(44, new Arg(0),[14],[[new ArgProj(0, 0)]]), new Rule(44, new Arg(0),[45],[[new ArgProj(0, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[27, 43, 40, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[27, 42, 40, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(40, new Arg(0),[10],[[new ArgProj(0, 0)]]), new Rule(40, new Arg(0),[41],[[new ArgProj(0, 0)]]), new Rule(25, new FunApp("CommandAdj",[new Arg(0), new Arg(1), new Arg(2), new Arg(3)]),[27, 39, 37, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new ArgProj(3, 0)]]), new Rule(37, new Arg(0),[16],[[new ArgProj(0, 0)]]), new Rule(37, new Arg(0),[38],[[new ArgProj(0, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[36, 34, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig")]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[36, 32, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig")]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[36, 31, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig")]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[36, 29, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig")]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[36, 28, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig")]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[36, 26, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0), new Terminal("dig")]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[35, 34, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[35, 32, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[35, 31, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[35, 29, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[35, 28, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[35, 26, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[27, 34, 33],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[27, 32, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[27, 31, 30],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[27, 29, 22],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[27, 28, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(25, new FunApp("Command",[new Arg(0), new Arg(1), new Arg(2)]),[27, 26, 24],[[new ArgProj(0, 1), new ArgProj(0, 0), new ArgProj(1, 0), new ArgProj(2, 0)]]), new Rule(24, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariska")]]), new Rule(23, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariskas")]]), new Rule(22, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariskan")]]), new Rule(21, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariskans")]]), new Rule(20, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariskor")]]), new Rule(19, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariskors")]]), new Rule(18, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariskorna")]]), new Rule(17, new FunApp("Bulgarian",[]),[],[[new Terminal("Bulgariskornas")]]), new Rule(16, new FunApp("Available",[]),[],[[new Terminal("tillgänglig")]]), new Rule(15, new FunApp("Available",[]),[],[[new Terminal("tillgängligs")]]), new Rule(14, new FunApp("Available",[]),[],[[new Terminal("tillgängligt")]]), new Rule(13, new FunApp("Available",[]),[],[[new Terminal("tillgängligts")]]), new Rule(12, new FunApp("Available",[]),[],[[new Terminal("tillgängliga")]]), new Rule(11, new FunApp("Available",[]),[],[[new Terminal("tillgängligas")]]), new Rule(10, new FunApp("Available",[]),[],[[new Terminal("tillgängliga")]]), new Rule(9, new FunApp("Available",[]),[],[[new Terminal("tillgängligas")]]), new Rule(8, new FunApp("Available",[]),[],[[new Terminal("tillgängliga")]]), new Rule(7, new FunApp("Available",[]),[],[[new Terminal("tillgängligas")]]), new Rule(6, new FunApp("Available",[]),[],[[new Terminal("tillgängligare")]]), new Rule(5, new FunApp("Available",[]),[],[[new Terminal("tillgängligares")]]), new Rule(4, new FunApp("Available",[]),[],[[new Terminal("tillgängligast")]]), new Rule(3, new FunApp("Available",[]),[],[[new Terminal("tillgängligasts")]]), new Rule(2, new FunApp("Available",[]),[],[[new Terminal("tillgängligaste")]]), new Rule(1, new FunApp("Available",[]),[],[[new Terminal("tillgängligastes")]])],{Adjective:[37, 38, 16, 15, 44, 45, 14, 13, 12, 11, 40, 41, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1], Determiner:[95, 77, 91, 73, 93, 75, 87, 69, 39, 42, 43, 89, 71, 26, 28, 29, 85, 67, 94, 76, 90, 72, 92, 74, 86, 68, 46, 47, 48, 88, 70, 31, 32, 34, 84, 66], Float:[-3], Int:[-2], Noun:[96, 24, 30, 20, 81, 22, 33, 18, 79, 23, 83, 19, 80, 21, 82, 17, 78], Sentence:[25], String:[-1], Verb:[65, 49, 27, 36, 35, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50], _Var:[-4]}))}); diff --git a/src/runtime/javascript/empty.png b/src/runtime/javascript/empty.png Binary files differnew file mode 100644 index 000000000..35d9875df --- /dev/null +++ b/src/runtime/javascript/empty.png diff --git a/src/runtime/javascript/gfjseditor.js b/src/runtime/javascript/gfjseditor.js new file mode 100644 index 000000000..5deb86160 --- /dev/null +++ b/src/runtime/javascript/gfjseditor.js @@ -0,0 +1,1267 @@ +
+//Variable and Constant definitions
+
+var expColImg = new Array(2);
+expColImg[0] = new Image(12,12);
+expColImg[0].src = "minus.png";
+expColImg[1] = new Image(12,12);
+expColImg[1].src = "plus.png";
+expColImg[2] = new Image(12,12);
+expColImg[2].src = "empty.png";
+
+// Grammars
+var grammar = undefined;
+var editorGrammar = Editor;
+
+var selectedLanguage = "EditorEng";
+var selectedNode = "";
+var collapseBuffer = new Array();
+var abstractTree = new Fun ("?");
+
+var navigationControlString = new Array();
+var undoArray = new Array();
+var redoArray = new Array();
+var clipBoard;
+var refPageCounter = 0;
+
+var stringAbstractTree = undefined;
+var myTree = undefined;
+var parseTrees = undefined;
+
+var keys = new Array();
+keys ["Z"] = function() { clickUndo('actUndo'); }
+keys ["Y"] = function() { clickRedo('actRedo'); }
+keys ["R"] = function() { clickRefine('actRefine'); };
+keys ["V"] = function() { clickPaste('actPaste'); };
+keys ["X"] = function() { clickCut('actCut'); };
+keys ["C"] = function() { clickCopy('actCopy'); };
+keys ["D"] = function() { clickDelete('actDelete'); };
+keys ["E"] = function() { clickReplace('actReplace'); };
+keys ["W"] = function() { clickWrap('actWrap'); };
+keys ["P"] = function() { clickParse('actParse'); };
+keys ["N"] = function() { clickRandomNode('actRandomNode'); };
+keys ["T"] = function() { clickRandomTree('actRandomTree'); };
+keys ["%"] = function() { leftArrowKey(); };
+keys ["&"] = function() { upDownArrowKey(-1); };
+keys ["'"] = function() { rightArrowKey(); };
+keys ["("] = function() { upDownArrowKey( 1); };
+keys ["27"] = function() { clickEsc(); };
+
+function state(selectedNode, tree, collapseBuffer) {
+ this.selectedNode = selectedNode;
+ this.tree = grammar.abstract.copyTree(tree);
+ this.collapseBuffer = collapseBuffer;
+ return this;
+}
+
+function treeNode(name, caption) {
+ this.name = name;
+ this.caption = caption;
+ this.cat = "";
+ this.children = new Array();
+ this.collapsed = false;
+ return this;
+}
+
+treeNode.prototype.addChild = function (i, c) {
+ this.children[i] = c;
+}
+
+treeNode.prototype.hasChildren = function() {
+ return this.children.length;
+}
+
+/* -------------------------------------------------------------------------- */
+/* ----------------------------- GUI functions ----------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+// Creates an instance of the editor and stores it in the given HTML container.
+// Previous content is destroyed.
+function mkEditor(container, myGrammar) {
+ grammar = myGrammar;
+ myTree = treeFromAbstract(grammar.abstract.annotate(abstractTree, grammar.abstract.startcat), "0");
+ var holder = document.getElementById(container);
+ holder.innerHTML = "<div id='wrapper'><div id='absFrame'></div><div id='conFrame'></div><div id='actFrame'></div><div id='refFrame'></div><div id='messageFrame'></div><div id='clipboardFrame'></div></div>";
+ nodeClick('0', '?');
+}
+
+// Generates a tree from the string representation of an abstract tree contained in the element elementToParse
+function parseStringTree(elementToParse) {
+ stringAbstractTree = elementToParse;
+ abstractTree = grammar.abstract.handleLiterals(grammar.abstract.parseTree(document.getElementById(elementToParse).value, grammar.abstract.startcat));
+ myTree = treeFromAbstract(abstractTree, "0");
+ nodeClick("0");
+}
+
+// If a key is pressed and a function assigned to that key, calls the function
+function hotKeys(event) {
+ event = (event) ? event : ((window.event) ? event : null);
+ if (event) {
+ var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : event.keyCode);
+ if (keys[String.fromCharCode(charCode).toUpperCase()] &&
+ !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
+ keys[String.fromCharCode(charCode).toUpperCase()]();
+ }
+ else if (keys["" + charCode] &&
+ !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
+ keys["" + charCode]();
+ }
+ else if (charCode >= "96" && charCode <= "105" &&
+ !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
+ keys["" + (charCode - 96)]();
+ }
+ }
+}
+
+// Clears "numeric" hotkeys
+function clearHotKeys() {
+ for (var key in keys) {
+ if ((parseInt(key) + 1) && (key != "27")) { keys[key] = function() { }; }
+ }
+}
+
+// Action to be performed when the up/down arrow key is pressed
+function upDownArrowKey(pos) {
+ var nodePos = getNavPos(selectedNode);
+ if ((nodePos > 0 && pos < 0) || (nodePos < navigationControlString.length - 1 && pos > 0)) {
+ nodeClick(navigationControlString[nodePos + pos]);
+ }
+}
+
+// Gets the position of a given node in the navigationControlString
+function getNavPos(nodeName) {
+ for (var i = 0, j = navigationControlString.length; i < j; i++) {
+ if (navigationControlString[i] == nodeName) { return i; };
+ }
+ return undefined;
+}
+
+// Given a name and a tree, gets the node in the tree with that name
+function getNode(nodeName, node) {
+ if (nodeName == node.name) {
+ return node;
+ }
+ else {
+ for (var i = 0, j = node.children.length; i < j; i++) {
+ var found = getNode(nodeName, node.children[i]);
+ if (found) { return found; }
+ }
+ }
+}
+
+// Action to be performed when the left arrow key is pressed
+function leftArrowKey() {
+ var node = getNode(selectedNode, myTree);
+ if (!node.collapsed && node.hasChildren()) {
+ signClick(node.name, node.caption);
+ }
+ else {
+ var parentNode = getParent(node.name, myTree);
+ if (parentNode) { nodeClick(parentNode.name); }
+ }
+}
+
+// Gets the parent of the selected node
+function getParent(nodeName, node) {
+ if (node.name == nodeName) {
+ return undefined;
+ }
+ else {
+ for (var i = 0, j = node.children.length; i < j; i++) {
+ if (node.children[i].name == nodeName) { return node; }
+ }
+ for (var i = 0, j = node.children.length; i < j; i++) {
+ var found = getParent(nodeName, node.children[i]);
+ if (found) { return found; }
+ }
+ }
+}
+
+// Action to be performed when the right arrow key is pressed
+function rightArrowKey() {
+ var node = getNode(selectedNode, myTree);
+ if (node.collapsed) {
+ signClick(node.name, node.caption);
+ }
+ else {
+ var firstDescendant = getfirstDescendant(node);
+ if (firstDescendant) {
+ nodeClick(firstDescendant.name);
+ }
+ }
+}
+
+// Gets the first descendant child of a node
+function getfirstDescendant(node) {
+ if (node.hasChildren() && !node.collapsed) { return node.children[0]; }
+ return undefined;
+}
+
+// Produces and displays an HTML representation of the tree
+function drawTree() {
+ var frame = document.getElementById("absFrame");
+ navigationControlString = new Array();
+ frame.innerHTML = "<ul id='tree'>" + getTree(myTree, 0) + "</ul>";
+ document.getElementById("link" + selectedNode).scrollIntoView(false);
+}
+
+// Produces an HTML representation of the tree
+function getTree(tree, level) {
+ navigationControlString[navigationControlString.length] = tree.name;
+ var htmlTree = new Array();
+ htmlTree.push("<li>");
+ if (tree.hasChildren()) {
+ htmlTree.push("<img class='tree-menu'");
+ if (tree.collapsed) {
+ htmlTree.push(" src='plus.png'");
+ }
+ else { htmlTree.push(" src='minus.png'"); }
+ htmlTree.push(" onclick='signClick(\"", tree.name, "\", \"", tree.caption, "\")' />");
+ }
+ else {
+ htmlTree.push("<img class='tree-menu' src='empty.png' />");
+ }
+ htmlTree.push("<a id='link", tree.name, "'");
+ if (document.getElementById("actRefine").className == "selected" ||
+ document.getElementById("actReplace").className == "selected" ||
+ document.getElementById("actWrap").className == "selected" ||
+ document.getElementById("actParse").className == "selected") {
+ htmlTree.push("class='treeGray' "); }
+ else if (selectedNode == tree.name) { htmlTree.push("class='treeSelected' "); }
+ else { htmlTree.push("class='tree' "); }
+ htmlTree.push("href='' onclick='nodeClick(\"", tree.name, "\"); return false'>");
+ if (tree.cat == "String" || tree.cat == "Int" || tree.cat == "Float") {
+ htmlTree.push(tree.caption.substring(tree.caption.lastIndexOf("_") + 1));
+ } else {
+ htmlTree.push(tree.caption);
+ }
+ htmlTree.push(" : ", tree.cat, "</a></li><ul>");
+ if (tree.hasChildren() && !tree.collapsed) {
+ for (var i = 0, j = tree.children.length; i < j; i++) {
+ htmlTree.push(getTree(tree.children[i], level + 1));
+ }
+ }
+ htmlTree.push("</ul>");
+ return htmlTree.join("");
+}
+
+// Linearizes and displays the abstract tree
+function drawLinearizedFrame() {
+ var frame = document.getElementById("conFrame");
+ frame.innerHTML = getLinearizedFrame();
+}
+
+// Linearizes the abstract tree and returns it in HTML form
+function getLinearizedFrame() {
+ var linearizedFrame = new Array();
+ for (var i in grammar.concretes) {
+ linearizedFrame.push("<h4>", i, "</h4>");
+ linearizedFrame.push("<p id='line", i, "'>");
+ var tokens = grammar.concretes[i].tagAndLinearize(abstractTree);
+ for (var j = 0, k = tokens.length; j < k; j++) {
+ linearizedFrame.push(createLinearized(tokens[j]));
+ }
+ linearizedFrame.push("</p>");
+ }
+ linearizedFrame.push("<h4>Abstract</h4>");
+ linearizedFrame.push("<p id='lineAbstract'>", createLinearizedFromAbstract(myTree, "0"), "</p>");
+ return linearizedFrame.join("");
+}
+
+// Creates an HTML representation of a linearization of an abstract tree
+function createLinearized(token) {
+ var node = getNode(token.tag, myTree);
+ var linearized = new Array()
+ linearized.push("<span id='", token.tag, "' class=");
+ if (node.name.substr(0, selectedNode.length) == selectedNode) {
+ linearized.push("'selected'");
+ }
+ else {
+ linearized.push("'normal'");
+ }
+ if (token == "&-") { linearized.push("<br />"); }
+ else { linearized.push(" onclick='nodeClick(\"", node.name, "\");'> ", token, " </span>"); }
+ return linearized.join("");
+}
+
+// Creates an HTML representation of the abstract tree
+function createLinearizedFromAbstract(node, path, prec) {
+ var linearized = new Array();
+ linearized.push("<span id='", path, "' class=");
+ if (node.name.substr(0, selectedNode.length) == selectedNode) {
+ linearized.push("'selected'");
+ }
+ else {
+ linearized.push("'normal'");
+ }
+ linearized.push(" onclick='nodeClick(\"", node.name, "\");'>");
+ if (node.children.length) { linearized.push(" ("); }
+ if (node.cat == "String" || node.cat == "Int" || node.cat == "Float") {
+ linearized.push(" ", node.caption.substring(node.caption.lastIndexOf("_") + 1), " ");
+ } else {
+ linearized.push(" ", node.caption, " ");
+ }
+ for (var i = 0, j = node.children.length; i < j; i++) {
+ linearized.push(createLinearizedFromAbstract(node.children[i], path + "-" + i, 1));
+ }
+ if (node.children.length) { linearized.push(") "); }
+ linearized.push("</span>");
+ return linearized.join("");
+}
+
+// Expands/Collapses node
+function signClick(name, caption) {
+ myTree = expandCollapse(myTree, name);
+ nodeClick(name);
+}
+
+// Sets the "collapsed" property of a given node
+function expandCollapse(node, name) {
+ if (node.name == name) {
+ if (wasCollapsed(node.name)) { removeFromCollapseBuffer(node.name); }
+ else { collapseBuffer[collapseBuffer.length] = node.name; }
+ node.collapsed ^= true;
+ }
+ else {
+ for (var i = 0, j = node.children.length; i < j; i++) {
+ expandCollapse(node.children[i], name);
+ }
+ }
+ return node;
+}
+
+// Checks if a node was collapsed on the previous cycle
+function wasCollapsed(nodeName) {
+ for (var i = 0, j = collapseBuffer.length; i < j; i++) {
+ if (nodeName == collapseBuffer[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Removes a node from the collapseBuffer array
+function removeFromCollapseBuffer(nodeName) {
+ var newBuffer = new Array();
+ for (var i = 0, j = collapseBuffer.length; i < j; i++) {
+ if (nodeName != collapseBuffer[i]) {
+ newBuffer[newBuffer.length] = collapseBuffer[i];
+ }
+ }
+ collapseBuffer = newBuffer;
+}
+
+// Selects a node
+function nodeClick(name) {
+ if ((document.getElementById("actRefine") && document.getElementById("actRefine").className == "selected") ||
+ (document.getElementById("actReplace") && document.getElementById("actReplace").className == "selected") ||
+ (document.getElementById("actWrap") && document.getElementById("actWrap").className == "selected") ||
+ (document.getElementById("actTree") && document.getElementById("actTree").className == "selected")) {
+ return; }
+ selectedNode = name;
+ if (stringAbstractTree) {
+ document.getElementById(stringAbstractTree).value = abstractTree.show();
+ }
+ document.getElementById("actFrame").innerHTML = showActions();
+ document.getElementById("refFrame").innerHTML = "";
+ document.getElementById("messageFrame").innerHTML = showLanguages();
+ document.getElementById(selectedLanguage).className = "selected";
+ applyLanguage();
+ drawTree();
+ drawLinearizedFrame();
+}
+
+// Shows the available languages for the editor
+function showLanguages() {
+ var languages = new Array();
+ languages.push("<table class='language' id='languagesTable'>",
+ "<tr id='langs' class='language'>",
+ "<td class='language' id='EditorDan' title='Label Bulgarian' onclick='clickLanguage(\"\")'>Bulgarian</td>",
+ "<td class='language' id='EditorDan' title='Label Danish' onclick='clickLanguage(\"\")'>Danish</td>",
+ "<td class='language' id='EditorEng' title='Label English' onclick='clickLanguage(\"EditorEng\")'>English</td>",
+ "<td class='language' id='EditorFin' title='Label Finnish' onclick='clickLanguage(\"\")'>Finnish</td>",
+ "<td class='language' id='EditorFre' title='Label French' onclick='clickLanguage(\"EditorFre\")'>French</td>",
+ "<td class='language' id='EditorGer' title='Label German' onclick='clickLanguage(\"\")'>German</td>",
+ "<td class='language' id='EditorIta' title='Label Italian' onclick='clickLanguage(\"\")'>Italian</td>",
+ "<td class='language' id='EditorNor' title='Label Norwegian' onclick='clickLanguage(\"\")'>Norwegian</td>",
+ "<td class='language' id='EditorRus' title='Label Russian' onclick='clickLanguage(\"\")'>Russian</td>",
+ "<td class='language' id='EditorSpa' title='Label Spanish' onclick='clickLanguage(\"EditorSpa\")'>Spanish</td>",
+ "<td class='language' id='EditorSwe' title='Label Swedish' onclick='clickLanguage(\"EditorSwe\")'>Swedish</td></tr>",
+ "</table>");
+ return languages.join("");
+}
+
+// Selects the language to use in the editor
+function clickLanguage(lang) {
+ if (lang) {
+ var tdsToClear = document.getElementById("languagesTable").getElementsByTagName("td");
+ for (var i = 0, j = tdsToClear.length; i < j; i++) {
+ if (tdsToClear[i].className == "selected") { tdsToClear[i].className = "language"; }
+ }
+ document.getElementById(lang).className = "selected";
+ selectedLanguage = lang;
+ applyLanguage();
+ }
+}
+
+// Applies a language to the editor
+function applyLanguage() {
+ var langsToLinearize = document.getElementById("languagesTable").getElementsByTagName("td");
+ for (var i = 0, j = langsToLinearize.length; i < j; i++) {
+ var absStr = langsToLinearize[i].getAttribute("title");
+ var lin = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(absStr, editorGrammar.abstract.startcat));
+ lin = lin.substring(0,1).toUpperCase().concat(lin.substring(1))
+ if (!langsToLinearize[i].firstChild) {
+ var txt = document.createTextNode(lin);
+ langsToLinearize[i].appendChild(txt);
+ }
+ else {
+ langsToLinearize[i].firstChild.nodeValue = lin;
+ }
+ }
+ var actionsToLinearize = document.getElementById("actionsTable").getElementsByTagName("td");
+ for (var i = 0, j = actionsToLinearize.length; i < j; i++) {
+ if (actionsToLinearize[i].className == "action") {
+ var absStr = actionsToLinearize[i].getAttribute("title");
+ var lin = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(absStr, editorGrammar.abstract.startcat));
+ lin = lin.substring(0,1).toUpperCase().concat(lin.substring(1))
+ if (!actionsToLinearize[i].firstChild) {
+ var txt = document.createTextNode(lin);
+ actionsToLinearize[i].appendChild(txt);
+ }
+ else {
+ actionsToLinearize[i].firstChild.nodeValue = lin;
+ }
+ }
+ }
+ var messageToLinearize = document.getElementById("refgenRefRandom");
+ if (messageToLinearize) {
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("RandomlyCommand Select IndefSgDet Refinement", editorGrammar.abstract.startcat));
+ messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1));
+ }
+ var messageToLinearize = document.getElementById("nextRefsNext");
+ if (messageToLinearize) {
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat));
+ messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1));
+ }
+ messageToLinearize = document.getElementById("nextRefsPrevious");
+ if (messageToLinearize) {
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat));
+ messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1));
+ }
+ var messageToLinearize = document.getElementById("nextWrapsNext");
+ if (messageToLinearize) {
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat));
+ messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1));
+ }
+ messageToLinearize = document.getElementById("nextWrapsPrevious");
+ if (messageToLinearize) {
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat));
+ messageToLinearize.firstChild.firstChild.nodeValue = msg.substring(0,1).toUpperCase().concat(msg.substring(1));
+ }
+}
+
+// Shows the available actions for a node
+function showActions(caption) {
+ var node = getNode(selectedNode, myTree);
+ var abstractNode = getNodeFromAbstract(abstractTree, node.name, "0");
+ var actions = new Array();
+ actions.push("<table class='action' id='actionsTable'>");
+ if (undoArray.length) {
+ actions.push(createAction("Undo", "action", "SingleWordCommand Undo", "Z")); }
+ else { actions.push(createAction("Undo", "unavailable", "SingleWordCommand Undo", "Z")); };
+ if (redoArray.length) {
+ actions.push(createAction("Redo", "action", "SingleWordCommand Redo", "Y")); }
+ else { actions.push(createAction("Redo", "unavailable", "SingleWordCommand Redo", "Y")); }
+ if (node.caption == "?") {
+ actions.push(createAction("Cut", "unavailable", "SingleWordCommand Cut", "X"));
+ actions.push(createAction("Copy", "unavailable", "SingleWordCommand Copy", "C"));
+ var AbsNodeType = abstractNode.type;
+ if (clipBoard && (AbsNodeType == grammar.abstract.getCat(clipBoard.name))) {
+ actions.push(createAction("Paste", "action", "SingleWordCommand Paste", "V"));
+ }
+ else { actions.push(createAction("Paste", "unavailable", "SingleWordCommand Paste", "V")); }
+ actions.push(createAction("Delete", "unavailable", "SingleWordCommand Delete", "D"));
+ actions.push(createAction("Refine", "action", "SingleWordCommand Refine", "R"));
+ actions.push(createAction("Replace", "unavailable", "SingleWordCommand Replace", "E"));
+ actions.push(createAction("Wrap", "unavailable", "SingleWordCommand Wrap", "W"));
+ for (var i in grammar.concretes) {
+ if (grammar.concretes[i].parser) {
+ actions.push(createAction("Parse", "action", "Command Parse IndefSgDet String_N", "P"));
+ } else { actions.push(createAction("Parse", "unavailable", "Command Parse IndefSgDet String_N", "P")); }
+ break;
+ }
+ }
+ else if (node.caption) {
+ actions.push(createAction("Cut", "action", "SingleWordCommand Cut", "X"));
+ actions.push(createAction("Copy", "action", "SingleWordCommand Copy", "C"));
+ actions.push(createAction("Paste", "unavailable", "SingleWordCommand Paste", "V"));
+ actions.push(createAction("Delete", "action", "SingleWordCommand Delete", "D"));
+ actions.push(createAction("Refine", "unavailable", "SingleWordCommand Refine", "R"));
+ actions.push(createAction("Replace", "action", "SingleWordCommand Replace", "E"));
+ actions.push(createAction("Wrap", "action", "SingleWordCommand Wrap", "W"));
+ actions.push(createAction("Parse", "unavailable", "Command Parse IndefSgDet String_N", "P"));
+ }
+ if (node && !abstractNode.isComplete()) {
+ actions.push(createAction("RandomNode", "action", "RandomlyCommand Refine DefSgDet Node", "N"));
+ }
+ else {
+ actions.push(createAction("RandomNode", "unavailable", "RandomlyCommand Refine DefSgDet Node", "N"));
+ }
+ if (!abstractTree.isComplete()) {
+ actions.push(createAction("RandomTree", "action", "RandomlyCommand Refine DefSgDet Tree", "T"));
+ }
+ else {
+ actions.push(createAction("RandomTree", "unavailable", "RandomlyCommand Refine DefSgDet Tree", "T"));
+ }
+ actions.push("</table>");
+ return actions.join("");
+
+}
+
+// Creates an action
+function createAction(actionName, className, caption, hotKey) {
+ return "<tr id='act" + actionName + "' class='" + className +"' onclick='click" +
+ actionName + "(\"act" + actionName + "\")'><td class='action' title='" +
+ caption + "'>" + caption + "</td><td class='hotKey'>(" + hotKey + ")</td></tr>";
+}
+
+// When the "Refine" action is selected, gets the appropriate refinements for a node
+function clickRefine(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ if (selectedNode) {
+ refPageCounter = 0;
+ var node = getNodeFromAbstract(abstractTree, selectedNode, "0");
+ if (node.type == "String" || node.type == "Int" || node.type == "Float") {
+ var newType = undefined;
+ var newTypeCat = node.type + "_Literal_";
+ switch(node.type)
+ {
+ case "String":
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("Command Enter IndefSgDet String_N", editorGrammar.abstract.startcat));
+ newType = prompt(msg.substring(0,1).toUpperCase().concat(msg.substring(1)),'String');
+ if (!newType) { newType = "AutoString"; }
+ break;
+ case "Int":
+ while (isNaN(newType) || (newType && newType.indexOf(".") != -1)) {
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("Command Enter IndefSgDet Integer_N", editorGrammar.abstract.startcat));
+ newType = prompt(msg.substring(0,1).toUpperCase().concat(msg.substring(1)),'Int');
+ }
+ if (!newType) { newType = "8"; }
+ break;
+ case "Float":
+ while (isNaN(newType)) {
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("Command Enter IndefSgDet Float_N", editorGrammar.abstract.startcat));
+ newType = prompt(msg.substring(0,1).toUpperCase().concat(msg.substring(1)),'Float');
+ }
+ if (!newType) { newType = "8.0"; }
+ if (newType.indexOf(".") == -1) { newType += ".0"; }
+ break;
+ }
+ if (node.type == "String") {
+ newTypeCat += "\"" + newType + "\"";
+ } else {
+ newTypeCat += newType;
+ }
+ if (!grammar.abstract.types[newTypeCat]) {
+ grammar.abstract.addType(newTypeCat, [], node.type);
+ for (var i in grammar.concretes) {
+ grammar.concretes[i].addRule(newTypeCat, function(cs){ return new Arr(new Str(newType));});
+ }
+ }
+ node.name = newTypeCat;
+ abstractTree = insertNode(abstractTree, selectedNode, "0", node);
+ document.getElementById("actFrame").innerHTML = showActions();
+ document.getElementById("refFrame").innerHTML = "";
+ clearHotKeys();
+ concludeAction();
+ } else {
+ document.getElementById("refFrame").innerHTML = showRefinements(selectedNode);
+ }
+ }
+ }
+}
+
+// Sets the className of actName to "selected" and grays out the other selections
+function highlightSelectedAction(actName) {
+ graySelections(actName);
+ document.getElementById(actName).className = "selected";
+ drawTree();
+}
+
+// Grays out all actions except one
+function graySelections(except) {
+ var refs = document.getElementById("actFrame").getElementsByTagName("tr");
+ for (var i = 0, j = refs.length; i < j; i++) {
+ if (refs[i].id != except) { refs[i].className = "closed"; }
+ }
+}
+
+// Pushes the abstract tree into the undo array and clears the redo array
+function pushUndoClearRedo() {
+ undoArray.push(new state(selectedNode, abstractTree, collapseBuffer));
+ redoArray.length = 0;
+}
+
+// Gets the refinements to display
+function showRefinements(nodeName) {
+ var refs = getAvailableRefinements(nodeName, abstractTree, grammar);
+ var rowsPerPage = 9;
+ var pages = Math.floor(refs.length / rowsPerPage);
+ var upperLimit;
+ if (pages != refPageCounter) { upperLimit = (rowsPerPage * refPageCounter) + rowsPerPage; }
+ else { upperLimit = refs.length; }
+ var refinements = new Array();
+ refinements.push("<table class='refinement'>");
+ var keyPos = 0;
+ refinements.push(ref_wrapToHtml("ref", "genRefRandom", "refinement", "", keyPos, "RandomlyCommand Select IndefSgDet Refinement"));
+ keys["" + keyPos] = mkRefHotKey("genRefRandom");
+ keyPos++;
+ for (var i = (rowsPerPage * refPageCounter), j = upperLimit; i < j; i++) {
+ refinements.push(ref_wrapToHtml("ref", refs[i], "refinement", "", keyPos, ""));
+ keys["" + keyPos] = mkRefHotKey(refs[i]);
+ keyPos++;
+ }
+ if (((refs.length % rowsPerPage == 0) && (pages - 1) > refPageCounter) ||
+ ((refs.length % rowsPerPage != 0) && pages > refPageCounter) ) {
+ refinements.push(ref_wrapNextRefsToHtml("nextRefs", "Next", "refinement", "+", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat))));
+ keys["107"] = mkRefNextRefsHotKey("Next");
+ }
+ if (0 < refPageCounter) {
+ refinements.push(ref_wrapNextRefsToHtml("nextRefs", "Previous", "refinement", "-", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat))));
+ keys["109"] = mkRefNextRefsHotKey("Previous");
+ }
+ refinements.push("</table>");
+ return refinements.join("");
+}
+
+// Creates an HTML representation of a Refinement/Wrap
+function ref_wrapToHtml(funct, name, className, arg, hotKeyPos, caption) {
+ var ref_wrapHtml = new Array();
+ ref_wrapHtml.push("<tr id='", funct, name, "' class=", className, " onclick='", funct, "Click(\"", name, "\"", arg, ")'><td class='", className, "'>");
+ if (caption) { ref_wrapHtml.push(editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(caption, editorGrammar.abstract.startcat))); }
+ else { ref_wrapHtml.push(name, " : ", refArgsToHtml(name), grammar.abstract.getCat(name)); }
+ ref_wrapHtml.push("</td><td class='hotKey'>(", hotKeyPos, ")</td></tr>");
+ return ref_wrapHtml.join("");
+}
+
+// Creates the function to be used by a "numeric" hot key
+function mkRefHotKey(refName) {
+ return function() { if (document.getElementById("ref" + refName)) { refClick(refName); } }
+}
+
+// Creates an HTML representation of the Next/Previous Refinement/Wrap page
+function ref_wrapNextRefsToHtml(funct, name, className, hotKeyPos, caption) {
+ var ref_wrapHtml = new Array();
+ ref_wrapHtml.push("<tr id='", funct, name, "' class=", className, " onclick='", funct, "Click(\"", name, "\")'><td class='", className, "'>");
+ ref_wrapHtml.push(caption);
+ ref_wrapHtml.push("</td><td class='hotKey'>(", hotKeyPos, ")</td></tr>");
+ return ref_wrapHtml.join("");
+}
+
+// Creates the function to be used by a "+"/"-" hot key
+function mkRefNextRefsHotKey(refName) {
+ return function() { if (document.getElementById("nextRefs" + refName)) { nextRefsClick(refName); } }
+}
+
+// Creates a string representation of the arguments of a refinement
+function refArgsToHtml(fun) {
+ var args = new Array();
+ for (var i = 0, j = grammar.abstract.types[fun].args.length; i < j; i++) {
+ args.push(grammar.abstract.types[fun].args[i], " -> ");
+ }
+ return args.join("");
+}
+
+// Gets the type of a meta variable
+function getMetaType(absNode, route, currRoute) {
+ if (route == currRoute && absNode.isMeta()) {
+ return absNode.type;
+ }
+ else {
+ for (var i = 0, j = absNode.args.length; i < j; i++) {
+ var found = getMetaType(absNode.args[i], route, currRoute + "-" + i);
+ if (found) { return found };
+ }
+ }
+}
+
+// When the "Undo" action is selected, undoes the last action
+function clickUndo(actName) {
+ if (document.getElementById(actName).className == "action" && undoArray.length) {
+ highlightSelectedAction(actName);
+ redoArray.push(new state(selectedNode, abstractTree, collapseBuffer));
+ var prevState = undoArray.pop();
+ selectedNode = prevState.selectedNode;
+ abstractTree = grammar.abstract.copyTree(prevState.tree);
+ collapseBuffer = prevState.collapseBuffer;
+ if (abstractTree.isComplete()) { selectedNode = "0"; }
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ myTree = treeFromAbstract(abstractTree, "0");
+ nodeClick(selectedNode);
+ }
+}
+
+// When the "Redo" action is selected, redoes the last action
+function clickRedo(actName) {
+ if (document.getElementById(actName).className == "action" && redoArray.length) {
+ highlightSelectedAction(actName);
+ undoArray.push(new state(selectedNode, abstractTree, collapseBuffer));
+ var nextState = redoArray.pop();
+ selectedNode = nextState.selectedNode;
+ abstractTree = grammar.abstract.copyTree(nextState.tree);
+ collapseBuffer = nextState.collapseBuffer;
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ myTree = treeFromAbstract(abstractTree, "0");
+ nodeClick(selectedNode);
+ }
+}
+
+// When the "Copy" action is selected, copies the selected node to the clipboard
+function clickCopy(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ if (selectedNode) {
+ clipBoard = grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0"));
+ document.getElementById("clipboardFrame").innerHTML = clipBoard.name + " : " + grammar.abstract.getCat(clipBoard.name);
+ nodeClick(selectedNode);
+ }
+ }
+}
+
+// When the "Cut" action is selected, deletes the selected node and copies it to the clipboard
+function clickCut(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ if (selectedNode) {
+ clipBoard = grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0"));
+ document.getElementById("clipboardFrame").innerHTML = clipBoard.name + " : " + grammar.abstract.getCat(clipBoard.name);
+ abstractTree = deleteNode(abstractTree, selectedNode, "0");
+ concludeAction();
+ }
+ }
+}
+
+// Annotates the abstract tree, creates a tree from the abstract tree and selects the next meta variable
+function concludeAction() {
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ myTree = treeFromAbstract(abstractTree, "0");
+ selectNextMeta();
+}
+
+// Selects the next meta variable available
+function selectNextMeta() {
+ nodeClick(selectedNode);
+ if (!abstractTree.isComplete()) {
+ var pathToNextMeta = "";
+ var nodePos = getNavPos(selectedNode);
+ while (1) {
+ if (nodePos == navigationControlString.length) { nodePos = 0; }
+ var node = getNode(navigationControlString[nodePos], myTree);
+ if (node.caption == "?") { pathToNextMeta = node.name; break; }
+ nodePos++;
+ }
+ expandAscendants(pathToNextMeta);
+ nodeClick(pathToNextMeta);
+ }
+}
+
+// Expands the ascendants of a given node
+function expandAscendants(nodeName) {
+ var nodePath = nodeName.split("-");
+ var currAscendant = nodePath.shift();
+ while (nodePath.length > 0) {
+ var node = getNode(currAscendant, myTree);
+ if (node.collapsed) {
+ myTree = expandCollapse(myTree, currAscendant);
+ }
+ currAscendant += "-" + nodePath.shift();
+ }
+}
+
+// When the "Paste" action is selected, pastes the contents of the clipboard into the selected node
+function clickPaste(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ if (selectedNode) {
+ abstractTree = insertNode(abstractTree, selectedNode, "0", grammar.abstract.copyTree(clipBoard));
+ concludeAction();
+ }
+ }
+}
+
+// When the "Delete" action is selected, deletes the selected node
+function clickDelete(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ if (selectedNode) {
+ abstractTree = deleteNode(abstractTree, selectedNode, "0");
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ myTree = treeFromAbstract(abstractTree, "0");
+ nodeClick(selectedNode);
+ }
+ }
+}
+
+// When the "Replace" action is selected, replaces the selected node with another refinement
+function clickReplace(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ if (selectedNode) {
+ refPageCounter = 0;
+ abstractTree = deleteNode(abstractTree, selectedNode, "0");
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ myTree = treeFromAbstract(abstractTree, "0");
+ drawTree();
+ document.getElementById("refFrame").innerHTML = showRefinements(selectedNode);
+ }
+ }
+}
+
+// When the "Wrap" action is selected, wraps around the selected node with another refinement
+function clickWrap(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ var node = getNode(selectedNode, myTree);
+ if (selectedNode) {
+ refPageCounter = 0;
+ var wrappers = showWrappers(node.caption);
+ document.getElementById("refFrame").innerHTML = wrappers;
+ if (wrappers.length <= 31) {
+ var lin = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("ErrorMessage Available Wrapper", editorGrammar.abstract.startcat));
+ alert(lin.substring(0,1).toUpperCase().concat(lin.substring(1)));
+ document.getElementById("actFrame").innerHTML = showActions();
+ nodeClick(selectedNode);
+ }
+ }
+ }
+}
+
+// Gets the wrappers to display
+function showWrappers(nodeCaption) {
+ var nodeType = grammar.abstract.types[nodeCaption].cat;
+ var rowsPerPage = 10;
+ var availWrappers = getAvailableWrappers(nodeType, grammar, selectedNode);
+ var pages = Math.floor(availWrappers.length / rowsPerPage);
+ var upperLimit;
+ if (pages != refPageCounter) { upperLimit = (rowsPerPage * refPageCounter) + rowsPerPage; }
+ else { upperLimit = availWrappers.length; }
+ var wrappers = new Array();
+ wrappers.push("<table class='wrapper'>");
+ var keyPos = 0;
+ for (var i = (rowsPerPage * refPageCounter), j = upperLimit; i < j; i++) {
+ wrappers.push(ref_wrapToHtml("wrap", availWrappers[i][0], "wrapper", ", " + availWrappers[i][1], keyPos, ""));
+ keys["" + keyPos] = mkWrapHotKey(availWrappers[i][0], availWrappers[i][1]);
+ keyPos++;
+ }
+ if (((availWrappers.length % rowsPerPage == 0) && (pages - 1) > refPageCounter) ||
+ ((availWrappers.length % rowsPerPage != 0) && pages > refPageCounter) ) {
+ wrappers.push(ref_wrapNextRefsToHtml("nextWraps", "Next", "wrapper", "+", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat))));
+ keys["107"] = mkWrapNextRefsHotKey("Next");
+ }
+ if (0 < refPageCounter) {
+ wrappers.push(ref_wrapNextRefsToHtml("nextWraps", "Previous", "wrapper", "-", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat))));
+ keys["109"] = mkWrapNextRefsHotKey("Previous");
+ }
+ wrappers.push("</table>");
+ return wrappers.join("");
+}
+
+// Creates the function to be used by a "numeric" hot key
+function mkWrapHotKey(wrapName, argPos) {
+ return function() { if (document.getElementById("wrap" + wrapName)) { wrapClick(wrapName, argPos); } }
+}
+
+// Creates the function to be used by a "+"/"-" hot key
+function mkWrapNextRefsHotKey(wrapName) {
+ return function() { if (document.getElementById("nextWraps" + wrapName)) { nextWrapsClick(wrapName); } }
+}
+
+// When the "Parse" action is selected, asks the user for a string and parses it
+// to generate the subnode
+function clickParse(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ var node = getNode(selectedNode, myTree);
+ if (selectedNode) {
+ refPageCounter = 0;
+ parseTrees = undefined;
+ var msg = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("Command Enter IndefSgDet String_N", editorGrammar.abstract.startcat));
+ var string = prompt(msg.substring(0,1).toUpperCase().concat(msg.substring(1)),'String');
+ if (string || string == "") {
+ for (var i in grammar.concretes) {
+ parseTrees = grammar.concretes[i].parser.parseString(string, node.cat);
+ if (parseTrees.length == 1) {
+ pushUndoClearRedo();
+ abstractTree = insertNode(abstractTree, selectedNode, "0", grammar.abstract.copyTree(grammar.abstract.handleLiterals(parseTrees[0], node.cat)));
+ document.getElementById("actFrame").innerHTML = showActions();
+ document.getElementById("refFrame").innerHTML = "";
+ clearHotKeys();
+ concludeAction();
+ return false;
+ } else if (parseTrees.length > 1) {
+ document.getElementById("refFrame").innerHTML = showTrees();
+ return false;
+ }
+ }
+ } else { nodeClick(selectedNode); return false; }
+ var lin = editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("ErrorMessage Available Tree", editorGrammar.abstract.startcat));
+ alert(lin.substring(0,1).toUpperCase().concat(lin.substring(1)));
+ }
+ nodeClick(selectedNode);
+ }
+}
+
+// Displays the parse trees in the refinements panel
+function showTrees() {
+ var rowsPerPage = 10;
+ var pages = Math.floor(parseTrees.length / rowsPerPage);
+ var upperLimit;
+ if (pages != refPageCounter) { upperLimit = (rowsPerPage * refPageCounter) + rowsPerPage; }
+ else { upperLimit = parseTrees.length; }
+ var htmlTrees = new Array();
+ htmlTrees.push("<table class='tree'>");
+ var keyPos = 0;
+ for (var i = (rowsPerPage * refPageCounter), j = upperLimit; i < j; i++) {
+ htmlTrees.push(treeToHtml(i, keyPos, ""));
+ keys["" + keyPos] = mkTreeHotKey(i, keyPos);
+ keyPos++;
+ }
+ if (((parseTrees.length % rowsPerPage == 0) && (pages - 1) > refPageCounter) ||
+ ((parseTrees.length % rowsPerPage != 0) && pages > refPageCounter) ) {
+ htmlTrees.push(ref_wrapNextRefsToHtml("nextTrees", "Next", "tree", "+", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Next Page", editorGrammar.abstract.startcat))));
+ keys["107"] = mkTreeNextRefsHotKey("Next");
+ }
+ if (refPageCounter > 0) {
+ htmlTrees.push(ref_wrapNextRefsToHtml("nextTrees", "Previous", "tree", "-", editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree("CommandAdj Show DefSgDet Previous Page", editorGrammar.abstract.startcat))));
+ keys["109"] = mkTreeNextRefsHotKey("Previous");
+ }
+ htmlTrees.push("</table>");
+ return htmlTrees.join("");
+}
+
+// Creates an HTML representation of a parse Tree to be shown in the refinements panel
+function treeToHtml(i, hotKeyPos, caption) {
+ var htmlTree = new Array();
+ htmlTree.push("<tr id='tree", hotKeyPos, "' class='tree' onclick='treeClick(", i, ")'><td class='tree'>");
+ if (caption) { htmlTree.push(editorGrammar.concretes[selectedLanguage].linearize(editorGrammar.abstract.parseTree(caption, editorGrammar.abstract.startcat))); }
+ else { htmlTree.push(parseTrees[i].show()); }
+ htmlTree.push("</td><td class='hotKey'>(", hotKeyPos, ")</td></tr>");
+ return htmlTree.join("");
+}
+
+// Creates the function to be used by a "numeric" hot key
+function mkTreeHotKey(i, keyPos) {
+ return function() { if (document.getElementById("tree" + keyPos)) { treeClick(i); } }
+}
+
+// Creates the function to be used by a "+"/"-" hot key
+function mkTreeNextRefsHotKey(treeName) {
+ return function() { if (document.getElementById("nextTrees" + treeName)) { nextTreesClick(treeName); } }
+}
+
+
+// When the "RandomNode" action is selected, refines the node at random
+function clickRandomNode(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ if (selectedNode) {
+ var tempTree = grammar.abstract.copyTree(abstractTree);
+ abstractTree = insertNode(tempTree, selectedNode, "0", grammar.abstract.copyTree(fillSubTree(grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0")), grammar)));
+ concludeAction();
+ }
+ }
+}
+
+// When the "RandomTree" action is selected, refines the tree at random
+function clickRandomTree(actName) {
+ if (document.getElementById(actName).className == "action") {
+ highlightSelectedAction(actName);
+ pushUndoClearRedo();
+ abstractTree = grammar.abstract.copyTree(fillSubTree(abstractTree, grammar));
+ concludeAction();
+ }
+}
+
+// If a node is selected and is of type meta, it refines the node with a type refName
+function refClick(refName) {
+ if (selectedNode) {
+ if (refName == "genRefRandom") {
+ var refs = getAvailableRefinements(selectedNode, abstractTree, grammar);
+ refName = refs[Math.floor(refs.length * Math.random())];
+ }
+ abstractTree = refineAbstractTree(abstractTree, selectedNode, "0", refName);
+ document.getElementById("actFrame").innerHTML = showActions();
+ document.getElementById("refFrame").innerHTML = "";
+ clearHotKeys();
+ concludeAction();
+ }
+}
+
+// Creates a tree from an abstract tree
+function treeFromAbstract(abstractNode, name) {
+ var node = new treeNode(name, abstractNode.name);
+ if (node.caption == "?") {
+ node.cat = abstractNode.type; }
+ else {
+ if (grammar.abstract.types[node.caption]) {
+ node.cat = grammar.abstract.getCat(node.caption);
+ } else {
+ node.cat = node.caption.substring(0, node.caption.indexOf("_"));
+ grammar.abstract.addType(node.caption, [], node.cat);
+ var linStr = undefined;
+ if (node.cat == "String") {
+ linStr = node.caption.substring(node.caption.indexOf("\"") + 1, node.caption.length - 1);
+ } else {
+ linStr = node.caption.substring(node.caption.lastIndexOf("_") + 1)
+ }
+ for (var i in grammar.concretes) {
+ grammar.concretes[i].addRule(node.caption, function(cs){ return new Arr(new Str(linStr));});
+ }
+ }
+ }
+ if (wasCollapsed(node.name)) { node.collapsed = true; }
+ for (var i = 0, j = abstractNode.args.length; i < j; i++) {
+ node.addChild(i, treeFromAbstract(abstractNode.args[i], name + "-" + i));
+ }
+ return node
+}
+
+// Wraps a refinement around a node
+function wrapClick(wrapName, argPos) {
+ if (selectedNode) {
+ var tempNode = createRefinement(wrapName);
+ tempNode.setArg(argPos, grammar.abstract.copyTree(getNodeFromAbstract(abstractTree, selectedNode, "0")));
+ abstractTree = insertNode(abstractTree, selectedNode, "0", tempNode);
+ var cat = grammar.abstract.getCat(tempNode.name);
+ if (selectedNode == "0" && cat != grammar.abstract.startcat) {
+ grammar.abstract.startcat = cat;
+ }
+ document.getElementById("actFrame").innerHTML = showActions();
+ document.getElementById("refFrame").innerHTML = "";
+ clearHotKeys();
+ concludeAction();
+ }
+}
+
+// Wraps a refinement around a node
+function treeClick(i) {
+ if (selectedNode) {
+ pushUndoClearRedo();
+ var node = getNode(selectedNode, myTree);
+ var tempNode = grammar.abstract.copyTree(grammar.abstract.handleLiterals(parseTrees[i], node.cat));
+ abstractTree = insertNode(abstractTree, selectedNode, "0", tempNode);
+ document.getElementById("actFrame").innerHTML = showActions();
+ document.getElementById("refFrame").innerHTML = "";
+ clearHotKeys();
+ concludeAction();
+ }
+}
+
+// Handler for the escape key
+function clickEsc() {
+ if ((document.getElementById("actRefine").className == "selected" ||
+ document.getElementById("actReplace").className == "selected" ||
+ document.getElementById("actWrap").className == "selected" ||
+ document.getElementById("actParse").className == "selected") && undoArray.length) {
+ var prevState = undoArray.pop();
+ selectedNode = prevState.selectedNode;
+ abstractTree = grammar.abstract.copyTree(prevState.tree);
+ collapseBuffer = prevState.collapseBuffer;
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ myTree = treeFromAbstract(abstractTree, "0");
+ document.getElementById("actFrame").innerHTML = showActions();
+ if (selectedNode) { nodeClick(selectedNode) }
+ }
+}
+
+// If there are over ten refinements available shows only the selected nine
+function nextRefsClick(refName) {
+ if (refName == "Next") { refPageCounter++; } else { refPageCounter--; }
+ clearHotKeys();
+ document.getElementById("refFrame").innerHTML = showRefinements(selectedNode);
+}
+
+// If there are over ten wrappers available shows only the selected nine
+function nextWrapsClick(wrapName) {
+ if (wrapName == "Next") { refPageCounter++; } else { refPageCounter--; }
+ clearHotKeys();
+ var node = getNode(selectedNode, myTree);
+ document.getElementById("refFrame").innerHTML = showWrappers(node.caption);
+}
+
+// If there are over ten parse trees available shows only the selected nine
+function nextTreesClick(treeName) {
+ if (treeName == "Next") { refPageCounter++; } else { refPageCounter--; }
+ clearHotKeys();
+ document.getElementById("refFrame").innerHTML = showTrees();
+}
+
+/* -------------------------------------------------------------------------- */
+/* ---------- GUI independent functions to handle syntax editing ---------- */
+/* -------------------------------------------------------------------------- */
+
+// Gets the node rooted at the indicated path (route) in the tree absNode
+function getNodeFromAbstract(absNode, route, currRoute) {
+ if (route == currRoute) {
+ return absNode;
+ }
+ else {
+ for (var i = 0, j = absNode.args.length; i < j; i++) {
+ var found = getNodeFromAbstract(absNode.args[i], route, currRoute + "-" + i);
+ if (found) { return found; }
+ }
+ }
+}
+
+// Gets the first metavariable from the abstract tree rooted at the path route
+function getNextMetaFromAbstract(node, route) {
+ if (node.isMeta()) { return route; }
+ for (var i = 0, j = node.args.length; i < j; i++) {
+ var found = getNextMetaFromAbstract(node.args[i], route + "-" + i);
+ if (found) { return found; }
+ }
+}
+
+// Inserts the node into the abstract tree absNode at the path route
+function insertNode(absNode, route, currRoute, node) {
+ if (route == currRoute) {
+ return node;
+ }
+ else {
+ for (var i = 0, j = absNode.args.length; i < j; i++) {
+ absNode.setArg(i, insertNode(absNode.args[i], route, currRoute + "-" + i, node));
+ }
+ return absNode;
+ }
+}
+
+// Deletes the node rooted at the path route from the abstract tree absNode
+function deleteNode(absNode, route, currRoute) {
+ if (route == currRoute) {
+ return new Fun("?");
+ }
+ else {
+ for (var i = 0, j = absNode.args.length; i < j; i++) {
+ absNode.setArg(i, deleteNode(absNode.args[i], route, currRoute + "-" + i));
+ }
+ return absNode;
+ }
+}
+
+// Gets the available refinements for the node nodeName, which is in the tree
+// abstractTree, from those found in the grammar.
+function getAvailableRefinements(nodeName, abstractTree, grammar) {
+ var node = getNodeFromAbstract(abstractTree, nodeName, "0");
+ var metaType = node.type;
+ var refinements = new Array();
+ for (var fun in grammar.abstract.types) {
+ if (grammar.abstract.types[fun].cat == metaType) {
+ refinements[refinements.length] = fun;
+ }
+ }
+ return refinements;
+}
+
+// It refines the node rooted at the path route in the abstract tree absNode
+// with the refinement refName. Returns the refined abstract tree.
+function refineAbstractTree(absNode, route, currRoute, refName) {
+ if (route == currRoute && absNode.isMeta()) {
+ return createRefinement(refName);
+ }
+ else {
+ for (var i = 0, j = absNode.args.length; i < j; i++) {
+ absNode.setArg(i, refineAbstractTree(absNode.args[i], route, currRoute + "-" + i, refName));
+ }
+ return absNode;
+ }
+}
+
+// Creates a node of type refName object with the appropriate number of arguments
+function createRefinement(refName) {
+ var newRef = new Fun(refName);
+ for (var i = 0, j = grammar.abstract.types[refName].args.length; i < j; i++) {
+ newRef.setArg(i, new Fun("?"));
+ }
+ return newRef;
+}
+
+// Gets the available wrappers for a node of type nodeType found in the grammar
+function getAvailableWrappers(nodeType, grammar, top) {
+ var wrappers = new Array();
+ for (var fun in grammar.abstract.types) {
+ for (var i = 0, j = grammar.abstract.types[fun].args.length; i < j; i++) {
+ if (top != "0") {
+ if (grammar.abstract.types[fun].args[i] == nodeType && grammar.abstract.types[fun].cat == nodeType) {
+ wrappers[wrappers.length] = new Array(fun, i);
+ break;
+ }
+ } else {
+ if (grammar.abstract.types[fun].args[i] == nodeType) {
+ wrappers[wrappers.length] = new Array(fun, i);
+ break;
+ }
+ }
+ }
+ }
+ return wrappers;
+}
+
+// Instantiates metavariables found in the tree abstractTree with refinements
+// selected at random from those found in the grammar
+function fillSubTree(abstractTree, grammar) {
+ while (!abstractTree.isComplete()) {
+ var nodeToRefine = getNextMetaFromAbstract(abstractTree, "0");
+ if (nodeToRefine) {
+ var refs = getAvailableRefinements(nodeToRefine, abstractTree, grammar);
+ if (refs.length == 0) {
+ var node = getNodeFromAbstract(abstractTree, nodeToRefine, "0");
+ if (node.type == "String" || node.type == "Int" || node.type == "Float") {
+ var newType = undefined;
+ var newTypeCat = node.type + "_Literal_";
+ switch(node.type)
+ {
+ case "String":
+ newType = "AutoString";
+ break;
+ case "Int":
+ newType = "8";
+ break;
+ case "Float":
+ newType = "8.0";
+ break;
+ }
+ if (node.type == "String") {
+ newTypeCat += "\"" + newType + "\"";
+ } else {
+ newTypeCat += newType;
+ }
+ if (!grammar.abstract.types[newTypeCat]) {
+ grammar.abstract.addType(newTypeCat, [], node.type);
+ for (var i in grammar.concretes) {
+ grammar.concretes[i].addRule(newTypeCat, function(cs){ return new Arr(new Str(newType));});
+ }
+ }
+ node.name = newTypeCat;
+ abstractTree = insertNode(abstractTree, nodeToRefine, "0", node);
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ }
+ }
+ else {
+ var selectedRef = refs[Math.floor(refs.length * Math.random())];
+ abstractTree = refineAbstractTree(abstractTree, nodeToRefine, "0", selectedRef);
+ abstractTree = grammar.abstract.annotate(abstractTree, grammar.abstract.startcat);
+ }
+ }
+ }
+ return abstractTree;
+}
diff --git a/src/runtime/javascript/gflib-xhtml-voice.js b/src/runtime/javascript/gflib-xhtml-voice.js new file mode 100644 index 000000000..fd8660100 --- /dev/null +++ b/src/runtime/javascript/gflib-xhtml-voice.js @@ -0,0 +1,54 @@ +/* Output */ + +function sayText(text) { + document.voice_output_text = text; + activateForm("voice_output"); +} + +/* XHTML+Voice Utilities */ + +function activateForm(formid) { + var form = document.getElementById(formid); + var e = document.createEvent("UIEvents"); + e.initEvent("DOMActivate","true","true"); + form.dispatchEvent(e); +} + + +/* DOM utilities */ + +/* Gets the head element of the document. */ +function getHeadElement() { + var hs = document.getElementsByTagName("head"); + if (hs.length == 0) { + var head = document.createElement("head"); + document.documentElement.insertBefore(head, document.documentElement.firstChild); + return head; + } else { + return hs[0]; + } +} + +/* Gets the body element of the document. */ +function getBodyElement() { + var bs = document.getElementsByTagName("body"); + if (bs.length == 0) { + var body = document.createElement("body"); + document.documentElement.appendChild(body); + return body; + } else { + return bs[0]; + } +} + +/* Removes all the children of a node */ +function removeChildren(node) { + while (node.hasChildNodes()) { + node.removeChild(node.firstChild); + } +} + +function setText(node, text) { + removeChildren(node); + node.appendChild(document.createTextNode(text)); +} diff --git a/src/runtime/javascript/gflib.js b/src/runtime/javascript/gflib.js new file mode 100644 index 000000000..728655469 --- /dev/null +++ b/src/runtime/javascript/gflib.js @@ -0,0 +1,1128 @@ + +function GFGrammar(abstract, concretes) { + this.abstract = abstract; + this.concretes = concretes; +} + +/* Translates a string from any concrete syntax to all concrete syntaxes. + Uses the start category of the grammar. +*/ +GFGrammar.prototype.translate = function (input, fromLang, toLang) { + var outputs = new Object(); + var fromConcs = this.concretes; + if (fromLang) { + fromConcs = new Object(); + fromConcs[fromLang] = this.concretes[fromLang]; + } + var toConcs = this.concretes; + if (toLang) { + toConcs = new Object(); + toConcs[toLang] = this.concretes[toLang]; + } + for (var c1 in fromConcs) { + var p = this.concretes[c1].parser; + if (p) { + var trees = p.parseString(input, this.abstract.startcat); + if (trees.length > 0) { + outputs[c1] = new Array(); + for (var i in trees) { + outputs[c1][i] = new Object(); + for (var c2 in toConcs) { + outputs[c1][i][c2] = this.concretes[c2].linearize(trees[i]); + } + } + } + } + } + return outputs; +} + + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- LINEARIZATION ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +/* Extension to the String object */ + +String.prototype.tag = ""; +String.prototype.setTag = function (tag) { this.tag = tag; }; + +/* Abstract syntax trees */ +function Fun(name) { + this.name = name; + this.args = copy_arguments(arguments, 1); +} +Fun.prototype.print = function () { return this.show(0); } ; +Fun.prototype.show = function (prec) { + if (this.isMeta()) { + if (isUndefined(this.type)) { + return '?'; + } else { + var s = '?:' + this.type; + if (prec > 0) { + s = "(" + s + ")" ; + } + return s; + } + } else { + var s = this.name; + var cs = this.args; + for (var i in cs) { + s += " " + (isUndefined(cs[i]) ? "undefined" : cs[i].show(1)); + } + if (prec > 0 && cs.length > 0) { + s = "(" + s + ")" ; + } + return s; + } +}; +Fun.prototype.getArg = function (i) { + return this.args[i]; +}; +Fun.prototype.setArg = function (i,c) { + this.args[i] = c; +}; +Fun.prototype.isMeta = function() { + return this.name == '?'; +} ; +Fun.prototype.isComplete = function() { + if (this.isMeta()) { + return false; + } else { + for (var i in this.args) { + if (!this.args[i].isComplete()) { + return false; + } + } + return true; + } +} ; +Fun.prototype.isLiteral = function() { + return (/^[\"\d]/).test(this.name); +} ; + +/* Concrete syntax terms */ + +function Arr() { this.arr = copy_arguments(arguments, 0); } +Arr.prototype.tokens = function() { return this.arr[0].tokens(); }; +Arr.prototype.sel = function(i) { return this.arr[i.toIndex()]; }; +Arr.prototype.setTag = function(tag) { + for (var i = 0, j = this.arr.length; i < j; i++) { + this.arr[i].setTag(tag); + } +}; + +function Seq() { this.seq = copy_arguments(arguments, 0); } +Seq.prototype.tokens = function() { + var xs = new Array(); + for (var i in this.seq) { + var ys = this.seq[i].tokens(); + for (var j in ys) { + xs.push(ys[j]); + } + } + return xs; +}; +Seq.prototype.setTag = function(tag) { + for (var i = 0, j = this.seq.length; i < j; i++) { + this.seq[i].setTag(tag); + } +}; + +function Variants() { this.variants = copy_arguments(arguments, 0); } +Variants.prototype.tokens = function() { return this.variants[0].tokens(); }; +Variants.prototype.sel = function(i) { return this.variants[0].sel(i); }; +Variants.prototype.toIndex = function() { return this.variants[0].toIndex(); }; +Variants.prototype.setTag = function(tag) { + for (var i = 0, j = this.variants.length; i < j; i++) { + this.variants[i].setTag(tag); + } +}; + +function Rp(index,value) { this.index = index; this.value = value; } +Rp.prototype.tokens = function() { return new Array(this.index.tokens()); }; +Rp.prototype.sel = function(i) { return this.value.arr[i.toIndex()]; }; +Rp.prototype.toIndex = function() { return this.index.toIndex(); }; +Rp.prototype.setTag = function(tag) { this.index.setTag(tag) }; + +function Suffix(prefix,suffix) { + this.prefix = new String(prefix); + if (prefix.tag) { this.prefix.tag = prefix.tag; } + this.suffix = suffix; +}; +Suffix.prototype.tokens = function() { + var xs = this.suffix.tokens(); + for (var i in xs) { + xs[i] = new String(this.prefix + xs[i]); + xs[i].setTag(this.prefix.tag); + } + return xs; +}; +Suffix.prototype.sel = function(i) { return new Suffix(this.prefix, this.suffix.sel(i)); }; +Suffix.prototype.setTag = function(tag) { if (!this.prefix.tag) { this.prefix.setTag(tag); } }; + +function Meta() { } +Meta.prototype.tokens = function() { + var newString = new String("?"); + newString.setTag(this.tag); + return new Array(newString); +}; +Meta.prototype.toIndex = function() { return 0; }; +Meta.prototype.sel = function(i) { return this; }; +Meta.prototype.setTag = function(tag) { if (!this.tag) { this.tag = tag; } }; + +function Str(value) { this.value = value; } +Str.prototype.tokens = function() { + var newString = new String(this.value); + newString.setTag(this.tag); + return new Array(newString); +}; +Str.prototype.setTag = function(tag) { if (!this.tag) { this.tag = tag; } }; + +function Int(value) { this.value = value; } +Int.prototype.tokens = function() { + var newString = new String(this.value.toString()); + newString.setTag(this.tag); + return new Array(newString); +}; +Int.prototype.toIndex = function() { return this.value; }; +Int.prototype.setTag = function(tag) { if (!this.tag) { this.tag = tag; } }; + +/* Type annotation */ + +function GFAbstract(startcat, types) { + this.startcat = startcat; + this.types = types; +} +GFAbstract.prototype.addType = function(fun, args, cat) { + this.types[fun] = new Type(args, cat); +} ; +GFAbstract.prototype.getArgs = function(fun) { + return this.types[fun].args; +} +GFAbstract.prototype.getCat = function(fun) { + return this.types[fun].cat; +}; +GFAbstract.prototype.annotate = function(tree, type) { + if (tree.name == '?') { + tree.type = type; + } else { + var typ = this.types[tree.name]; + for (var i in tree.args) { + this.annotate(tree.args[i], typ.args[i]); + } + } + return tree; +} ; +GFAbstract.prototype.handleLiterals = function(tree, type) { + if (tree.name != '?') { + if (type == "String" || type == "Int" || type == "Float") { + tree.name = type + "_Literal_" + tree.name; + } else { + var typ = this.types[tree.name]; + for (var i in tree.args) { + this.handleLiterals(tree.args[i], typ.args[i]); + } + } + } + return tree; +} ; +/* Hack to get around the fact that our SISR doesn't build real Fun objects. */ +GFAbstract.prototype.copyTree = function(x) { + var t = new Fun(x.name); + if (!isUndefined(x.type)) { + t.type = x.type; + } + var cs = x.args; + if (!isUndefined(cs)) { + for (var i in cs) { + t.setArg(i, this.copyTree(cs[i])); + } + } + return t; +} ; +GFAbstract.prototype.parseTree = function(str, type) { + return this.annotate(this.parseTree_(str.match(/[\w\'\.\"]+|\(|\)|\?|\:/g), 0), type); +} ; +GFAbstract.prototype.parseTree_ = function(tokens, prec) { + if (tokens.length == 0 || tokens[0] == ")") { return null; } + var t = tokens.shift(); + if (t == "(") { + var tree = this.parseTree_(tokens, 0); + tokens.shift(); + return tree; + } else if (t == '?') { + var tree = this.parseTree_(tokens, 0); + return new Fun('?'); + } else { + var tree = new Fun(t); + if (prec == 0) { + var c, i; + for (i = 0; (c = this.parseTree_(tokens, 1)) !== null; i++) { + tree.setArg(i,c); + } + } + return tree; + } +} ; + +function Type(args, cat) { + this.args = args; + this.cat = cat; +} + +/* Linearization */ + +function GFConcrete(flags, rules, parser) { + this.flags = flags; + this.rules = rules; + if (parser) { + this.parser = parser; + } else { + this.parser = undefined; + } +} +GFConcrete.prototype.rule = function (name, cs) { + var r = this.rules[name]; + if (r) { + return this.rules[name](cs); + } else { + window.alert("Missing rule " + name); + } +}; +GFConcrete.prototype.addRule = function (name, f) { this.rules[name] = f; }; +GFConcrete.prototype.lindef = function (cat, v) { return this.rules[cat]([new Str(v)]); } ; +GFConcrete.prototype.linearize = function (tree) { + return this.unlex(this.linearizeToTerm(tree).tokens()); +}; +GFConcrete.prototype.linearizeToTerm = function (tree) { + if (tree.isMeta()) { + if (isUndefined(tree.type)) { + return new Meta(); + } else { + return this.lindef(tree.type, tree.name); + } + } else { + var cs = new Array(); + for (var i in tree.args) { + cs.push(this.linearizeToTerm(tree.args[i])); + } + if (tree.isLiteral()) { + return new Arr(new Str(tree.name)); + } else { + return this.rule(tree.name, cs); + } + } +}; +GFConcrete.prototype.unlex = function (ts) { + if (ts.length == 0) { + return ""; + } + + var noSpaceAfter = /^[\(\-\[]/; + var noSpaceBefore = /^[\.\,\?\!\)\:\;\-\]]/; + + var s = ""; + for (var i = 0; i < ts.length; i++) { + var t = ts[i]; + var after = i < ts.length-1 ? ts[i+1] : null; + s += t; + if (after != null && !t.match(noSpaceAfter) + && !after.match(noSpaceBefore)) { + s += " "; + } + } + return s; +}; +GFConcrete.prototype.tagAndLinearize = function (tree) { + return this.tagAndLinearizeToTerm(tree, "0").tokens(); +}; +GFConcrete.prototype.tagAndLinearizeToTerm = function (tree, route) { + if (tree.isMeta()) { + if (isUndefined(tree.type)) { + var newMeta = new Meta(); + newMeta.setTag(route); + return newMeta; + } else { + var newTerm = this.lindef(tree.type, tree.name); + newTerm.setTag(route); + return newTerm; + } + } else { + var cs = new Array(); + for (var i in tree.args) { + cs.push(this.tagAndLinearizeToTerm(tree.args[i], route + "-" + i)); + } + var newTerm = this.rule(tree.name, cs); + newTerm.setTag(route); + return newTerm; + } +}; + +/* Utilities */ + +/* from Remedial JavaScript by Douglas Crockford, http://javascript.crockford.com/remedial.html */ +function isString(a) { return typeof a == 'string'; } +function isArray(a) { return a && typeof a == 'object' && a.constructor == Array; } +function isUndefined(a) { return typeof a == 'undefined'; } +function isBoolean(a) { return typeof a == 'boolean'; } +function isNumber(a) { return typeof a == 'number' && isFinite(a); } +function isFunction(a) { return typeof a == 'function'; } + +function dumpObject (obj) { + if (isUndefined(obj)) { + return "undefined"; + } else if (isString(obj)) { + return '"' + obj.toString() + '"'; // FIXME: escape + } else if (isBoolean(obj) || isNumber(obj)) { + return obj.toString(); + } else if (isArray(obj)) { + var x = "["; + for (var i in obj) { + x += dumpObject(obj[i]); + if (i < obj.length-1) { + x += ","; + } + } + return x + "]"; + } else { + var x = "{"; + for (var y in obj) { + x += y + "=" + dumpObject(obj[y]) + ";" ; + } + return x + "}"; + } +} + + +function copy_arguments(args, start) { + var arr = new Array(); + for (var i = 0; i < args.length - start; i++) { + arr[i] = args[i + start]; + } + return arr; +} + +/* ------------------------------------------------------------------------- */ +/* -------------------------------- PARSING -------------------------------- */ +/* ------------------------------------------------------------------------- */ + + +function Parser(startcat, rules, cats) { + this.startcat = startcat; + this.rules = rules; + this.cats = cats; +} +Parser.prototype.showRules = function () { + var ruleStr = new Array(); + ruleStr.push(""); + for (i = 0, j = this.rules.length; i < j; i++) { + ruleStr.push(this.rules[i].show()); + } + return ruleStr.join(""); +}; +Parser.prototype.parseString = function (string, cat) { + var tokens = string.split(" "); + // remove empty tokens + for (var i = tokens.length - 1; i >= 0; i--) { + if (tokens[i] == "") { tokens.splice(i, 1); } + } + chart = new Chart(true); + predict(this.rules, tokens); + while (chart.updated) { + chart.updated = false; + completeAndConvert(); + scan(); + combine(); + } + var catToParse = this.startcat; + if (cat) { catToParse = cat; } + var goalRange = new Range(0, tokens.length); + if (tokens.length == 1 && tokens[0] == "") { goalRange = new EmptyRange(); } + var activeEdges = filterActiveEdges(); + var trees = new Array(); + for (var i = 0, j = this.cats[catToParse].length; i < j; i++) { + if (foundTarget(this.cats[catToParse][i], new Array(new Array(goalRange)))) { + trees = trees.concat(extractTrees(this.cats[catToParse][i], new Array(new Array(goalRange)), activeEdges, "")); + } + } + for (var i = trees.length - 1; i >= 0; i--) { + if (trees[i] == undefined) { trees.splice(i, 1); } + } + return trees; +}; + +// Rule Object Definition + +function Rule(cat, profile, args, linRec) { + this.cat = cat; + this.profile = profile; + this.args = args; + this.linRec = linRec; +} +Rule.prototype.show = function () { + var recStr = new Array(); + recStr.push(this.cat, " -> ", this.profile.show(), " [", this.args, "] = ", showLinRec(this.linRec, "")); + return recStr.join(""); +}; + +// Profile definitions + +// Function application +// The function (name) is applied to its arguments (args) +function FunApp(name, args) { + this.id = "FunApp"; + this.name = name; + this.args = args.slice(0); +} +FunApp.prototype.show = function () { + var funAppStr = new Array(); + funAppStr.push("(", this.name); + for (var i = 0, j = this.args.length; i < j; i++) { + funAppStr.push(this.args[i].show()); + } + funAppStr.push(")"); + return funAppStr.join(" "); +}; + +// Literal +function Lit(name) { + this.id = "Lit"; + this.name = name; +} +Lit.prototype.show = function () { return this.name; }; + +// Metavariable +function MetaVar() { this.id = "MetaVar"; } +MetaVar.prototype.show = function () { return "?"; }; + +// Argument +function Arg(i) { + this.id = "Arg"; + this.name = "_"; + this.i = i; +} +Arg.prototype.show = function () { + var argStr = new Array(); + argStr.push(this.id, "(", this.i, ")"); + return argStr.join(""); +}; + +// Unification +// The arguments (args) must be unified +function Unify(args){ + this.id = "Unify"; + this.args = args.slice(0); +} +Unify.prototype.show = function () { + var unifyStr = new Array(); + unifyStr.push("(", this.id); + for (var i = 0, j = this.args.length; i < j; i++) { + unifyStr.push(this.args[i].show()); + } + unifyStr.push(")"); + return unifyStr.join(" "); +}; + +// Definition of symbols present in linearization records + +// Object to represent argument projections in grammar rules +function ArgProj(i, label) { + this.id = "argProj"; + this.i = i; + this.label = label; +} +ArgProj.prototype.getId = function () { return this.id; }; +ArgProj.prototype.getArgNum = function () { return this.i }; +ArgProj.prototype.show = function () { + var argStr = new Array(); + argStr.push(this.i, this.label); + return argStr.join("."); +}; +ArgProj.prototype.isEqual = function (obj) { + return (this.id == obj.id && this.i == obj.i && this.label == obj.label); +} + +// Object to represent terminals in grammar rules +function Terminal (str) { + this.id = "terminal"; + this.str = str; +} +Terminal.prototype.getId = function () { return this.id; }; +Terminal.prototype.show = function () { + var terminalStr = new Array(); + terminalStr.push('"', this.str, '"'); + return terminalStr.join(""); +}; +Terminal.prototype.isEqual = function (obj) { + return (this.id == obj.id && this.str == obj.str); +} + +// Object to represent ranges in grammar rules +function Range (i, j) { + this.id = "range"; + this.i = i; + this.j = j; +} +Range.prototype.getId = function () { return this.id; }; +Range.prototype.show = function () { + var terminalStr = new Array(); + terminalStr.push("(", this.i, ",", this.j, ")"); + return terminalStr.join(""); +}; +Range.prototype.isEqual = function (obj) { + return (this.id == obj.id && this.i == obj.i && this.j == obj.j); +} + +// Object to represent the empty range in grammar rules +function EmptyRange () { + this.id = "emptyRange"; +} +EmptyRange.prototype.getId = function () { return this.id; }; +EmptyRange.prototype.show = function () { return "emptyRange" }; +EmptyRange.prototype.isEqual = function (obj) { + return (this.id == obj.id); +} + +// Chart Object Definition +function Chart(updated) { + this.passive = new Array(); + this.active = new Array(); + this.updated = updated; +} +Chart.prototype.show = function () { + var chartStr = new Array(); + chartStr.push("(", this.showPassive(), ", ", this.showActive(), ")"); + return chartStr.join(""); +}; +Chart.prototype.addPassiveEdge = function (cat, linRec) { + if (!this.passive[cat] || !this.passive[cat].length) { + this.passive[cat] = new Array(); + } + this.passive[cat].push(linRec); +}; +Chart.prototype.isPassiveElem = function (cat, linRec) { + if (this.passive[cat]) { + for (var i = 0, j = this.passive[cat].length; i < j; i++) { + if (linRecsAreEqual(this.passive[cat][i], linRec)) { + return true; + } + } + } + return false; +}; +Chart.prototype.showPassive = function () { + var edgesStr = new Array(); + edgesStr.push("[ "); + for (var cat in this.passive) { + for (var i = 0, j = this.passive[cat].length; i < j; i++) { + edgesStr.push("( ", cat, ", ", showLinRec(this.passive[cat][i], ""), ")"); + if (i != j - 1) { edgesStr.push(", "); }; + } + edgesStr.push(", "); + } + edgesStr.push(" ]"); + return edgesStr.join(""); + return edgesStr.join("") + "<br />"; +}; +Chart.prototype.addActiveEdge = function (cat, edge) { + if (!this.active[cat] || !this.active[cat].length) { + this.active[cat] = new Array(); + } + this.active[cat].push(edge); +}; +Chart.prototype.isActiveElem = function (cat, edge) { + if (this.active[cat]) { + for (var i = 0, j = this.active[cat].length; i < j; i++) { + var currentEdge = this.active[cat][i]; + if (currentEdge.name == edge.name && (areArgsEqual(currentEdge.args, edge.args)) && + currentEdge.currLabel == edge.currLabel && currentEdge.currLin.isEqual(edge.currLin) && + linRecsAreEqual(currentEdge.linFound, edge.linFound) && linRowsAreEqual(currentEdge.remLin, edge.remLin) && + linRecsAreEqual(currentEdge.remLinRows, edge.remLinRows) && + arraysOfLinRecsAreEqual(currentEdge.children, edge.children)) { + return true; + } + } + } + return false; +}; +Chart.prototype.showActive = function () { + var edgesStr = new Array() + edgesStr.push("[ "); + for (var cat in this.active) { + for (var i = 0, j = this.active[cat].length; i < j; i++) { + edgesStr.push("( ", this.active[cat][i].show(), " )"); + if (i != j - 1) { edgesStr.push(", "); }; + } + edgesStr.push(", "); + } + edgesStr.push(" ]"); + return edgesStr.join(""); +}; + +// Object to represent the active edges in a chart +function ActiveEdge(profile, cat, name, args, linFound, currLabel, currLin, remLin, remLinRows, children) { + this.profile = profile; + this.cat = cat; + this.name = name; + this.args = args; + this.linFound = linFound; + this.currLabel = currLabel; + this.currLin = currLin; + this.remLin = remLin; + this.remLinRows = remLinRows; + this.children = children.slice(0); +} +ActiveEdge.prototype.show = function () { + var linRecStr = new Array(); + linRecStr.push(this.profile.show(), ", ", this.cat, ", ", this.name, ", [ ", this.args, " ], ", showLinRec(this.linFound, ""), + ", ", this.currLabel, ", ", this.currLin.show(), ", ", showLinRow(this.remLin, " ++ "), + ", ", showLinRec(this.remLinRows, ""), ", [ "); + for (var i = 0, j = this.children.length; i < j; i++) { + linRecStr.push(showLinRec(this.children[i], "")); + if (i != j - 1) { linRecStr.push(", "); }; + } + linRecStr.push(" ]"); + return linRecStr.join(""); +}; + +function areArgsEqual(args1, args2) { + if (args1.length == args1.length && args1.join() == args2.join()) { + return true + } + return false; +} + +// Functions to manipulate linearization records + +// Returns a string representation of a linearization row +function showLinRow(linRow, separator) { + var linRowStr = new Array(); + linRowStr.push(" [ "); + for (var i = 0, j = linRow.length; i < j; i ++) { + linRowStr.push(linRow[i].show()); + if (i != j - 1) { linRowStr.push(separator) }; + } + linRowStr.push(" ] "); + return linRowStr.join(""); +} + +// Returns a string representation of a linearization record +function showLinRec(linRec, separator) { + var linRecStr = new Array(); + linRecStr.push(" [ "); + for (var i = 0, j = linRec.length; i < j; i ++) { + linRecStr.push(showLinRow(linRec[i], " ++ ")); + if (i != j - 1) { linRecStr.push(separator); }; + } + linRecStr.push(" ] "); + return linRecStr.join(""); +} + +// Checks if two linearization rows are equal +function linRowsAreEqual(linRow1, linRow2) { + if (linRow1.length == linRow2.length) { + for (var i = 0, j = linRow1.length; i < j; i++) { + if (linRow1[i].id && linRow2[i].id && !linRow1[i].isEqual(linRow2[i])) { + return false; + } + } + return true; + } + return false; +} + +// Checks if two linearization records are equal +function linRecsAreEqual(linRec1, linRec2) { + if (linRec1.length == linRec2.length) { + for (var i = 0, j = linRec1.length; i < j; i++) { + if (!linRowsAreEqual(linRec1[i], linRec2[i])) { return false; } + } + return true; + } + return false; +} + +// Checks if two arrays of linearization records are equal +function arraysOfLinRecsAreEqual(array1, array2) { + if (array1.length == array2.length) { + for (var i = 0, j = array1.length; i < j; i++) { + if (!linRecsAreEqual(array1[i], array2[i])) { return false; } + } + return true; + } + return false; +} + +// Functions to manipulate ranges (restriction and concatenation) + +// Concatenates two ranges +function rangeConcatLin (lin1, lin2) { + if (lin1.id == "range" && lin2.id == "range") { + if (lin1.j == lin2.i) { return (new Range(lin1.i, lin2.j)) } + } else if (lin1.id == "range" && lin2.id == "emptyRange") { return lin1; } + else if (lin1.id == "emptyRange" && lin2.id == "range") { return lin2; } + else if (lin1.id == "emptyRange" && lin2.id == "emptyRange") { return lin1; } + return undefined; +} + +// Performs range concatenation on a linearization row +function rangeConcatLins (lins) { + var newLins = new Array(); + newLins.push(lins.shift()); + while (lins.length > 0) { + if (!newLins[newLins.length - 1]) { return new Array(); } + if (newLins[newLins.length - 1].id == "range" && lins[0].id == "range") { + var rangeConcat = rangeConcatLin(newLins.pop(), lins[0]); + if (typeof rangeConcat == 'undefined') { return new Array(); } + newLins.push(rangeConcat); + lins.shift(); + } else { + newLins.push(lins.shift()); + } + } + return newLins; +} + +// Performs range restriction on an element of a linearization row +// while keeping track of the tokens that have been used +function rangeRestLinTerm(tokens, lin, rangesNotConsumed) { + if (lin.id == "argProj") { return new Array(lin); } + else if (lin.id == "terminal") { + var ranges = new Array(); + for (var i = 0, j = tokens.length; i < j; i++) { + if (tokens[i] == lin.str) { + ranges.push(new Range(i, i + 1)); + rangesNotConsumed[i] = undefined; + } + } + if (ranges.length == 0) { + return undefined; + } else { + return ranges; + } + } + else { return new Array(); } +} + +// Performs range restriction on a linearization record +// while keeping track of the tokens that have been used +function rangeRestRecTerm(linRec, tokens, rangesNotConsumed) { + var ranges = new Array(); + for (var i = 0, j = linRec.length; i < j; i++) { + var rangeRestLins = new Array(); + for (var k = 0, l = linRec[i].length; k < l; k++) { + rangeRestLins.push(rangeRestLinTerm(tokens, linRec[i][k], rangesNotConsumed)); + } + var combinedLins = combineLins(rangeRestLins); + if (typeof combinedLins != 'undefined') { + var filteredLins = new Array(); + if (combinedLins.length == 0) { + filteredLins.push(new Array()); + } else { + for (var m = 0, n = combinedLins.length; m < n; m++) { + var temp = rangeConcatLins(combinedLins[m]); + if (temp.length != 0) { + filteredLins.push(temp); + } + } + } + ranges.push(filteredLins); + } else { ranges.push(undefined); } + } + for (var k = 0, l = ranges.length; k < l; k++) { + if (ranges[k] == undefined) { return undefined; } + } + return combineLins(ranges); +} + +// Returns the combinations of the elements of an array of arrays +function combineLins(linss) { + if (linss.length > 0) { + var combinedLins = new Array(); + var lins = linss.shift(); + if (lins) { + if (lins.length != 0) { + var tail = combineLins(linss); + if (typeof tail == 'undefined') { return undefined; } + for (var i = 0, j = lins.length; i < j; i++) { + var head = new Array(); + head.push(lins[i]); + if (tail.length == 0) { combinedLins.push(head); } + else { + for (var k = 0, l = tail.length; k < l; k++) { + combinedLins.push(head.concat(tail[k])); + } + } + } + } else { return new Array(); } + } else { return undefined; } + return combinedLins; + } else { return new Array(); } +} + +// Inference Rules + +function predict(rules, tokens) { + var rangesNotConsumed = genRanges(tokens.length); + for (var i = 0, j = rules.length; i < j; i++) { + var currentRule = rules[i]; + var linRec = rangeRestRecTerm(currentRule.linRec, tokens, rangesNotConsumed); + if (linRec) { + for (var k = 0, l = linRec.length; k < l; k++) { + var currentRow = linRec[k].shift(); + var remlinRows = linRec[k]; + var children = new Array(); + for (var m = 0, n = currentRule.args.length; m < n; m++) { + children.push(new Array()); + } + var newActive = new ActiveEdge(currentRule.profile, currentRule.cat, currentRule.profile.name, currentRule.args, new Array(), 0, new EmptyRange(), currentRow, remlinRows, children); + if (!chart.isActiveElem(currentRule.cat, newActive)) { + chart.addActiveEdge(currentRule.cat, newActive); + chart.updated = true; + } + } + } + } + for (var i = 0, j = rangesNotConsumed.length; i < j; i++) { + if (rangesNotConsumed[i] != undefined) { + var cat = undefined; + if (isNaN(tokens[i])) { + cat = "-1"; + } else if (tokens[i].lastIndexOf(".") == -1) { + cat = "-2"; + } else { + cat = "-3"; + } + var lit = undefined; + if (cat == "-1") { + lit = "\"" + tokens[i] + "\""; + } else { + lit = tokens[i]; + } + var newActive = new ActiveEdge(new Lit(lit), cat, tokens[i], new Array(), new Array(), 0, new Range(i, i + 1), new Array(), new Array(), new Array()); + if (!chart.isActiveElem(cat, newActive)) { + chart.addActiveEdge(cat, newActive); + chart.updated = true; + } + } + } +} + +function genRanges(inputLength) { + var ranges = new Array(); + for (var i = 0; i < inputLength; i++) { + ranges.push(i); + } + return ranges; +} + +function completeAndConvert() { + for (var cat in chart.active) { + var currentEdge = chart.active[cat]; + for (var i = 0, j = currentEdge.length; i < j; i++) { + if (currentEdge[i].remLin.length == 0) { + if (currentEdge[i].remLinRows.length == 0) { + var linFound = currentEdge[i].linFound.slice(0); + linFound.push(new Array(currentEdge[i].currLin)); + if (!chart.isPassiveElem(cat, linFound)) { + chart.addPassiveEdge(cat, linFound); + chart.updated = true; + } + } else { + var linFound = currentEdge[i].linFound.slice(0); + linFound.push(new Array(currentEdge[i].currLin)); + var remLinRows = currentEdge[i].remLinRows.slice(0); + var currentRow = remLinRows.shift(); + var newActive = new ActiveEdge(currentEdge[i].profile, cat, currentEdge[i].name, currentEdge[i].args, linFound, linFound.length, new EmptyRange(), currentRow, remLinRows, currentEdge[i].children); + if (!chart.isActiveElem(cat, newActive)) { + chart.active[cat].push(newActive); + chart.updated = true; + } + } + } + } + } +} + +function scan() { + for (var cat in chart.active) { + var currentEdge = chart.active[cat]; + for (var i = 0, j = currentEdge.length; i < j; i++) { + if (currentEdge[i].remLin.length > 0 && currentEdge[i].remLin[0].id == "range") { + var newRange = rangeConcatLin(currentEdge[i].currLin, currentEdge[i].remLin[0]); + if (typeof newRange != 'undefined') { + var remLin = currentEdge[i].remLin.slice(0); + remLin.shift(); + var newActive = new ActiveEdge(currentEdge[i].profile, cat, currentEdge[i].name, currentEdge[i].args, currentEdge[i].linFound, currentEdge[i].currLabel, newRange, remLin, currentEdge[i].remLinRows, currentEdge[i].children); + if (!chart.isActiveElem(cat, newActive)) { + chart.active[cat].push(newActive); + chart.updated = true; + } + } + } + } + } +} + +function combine() { + for (var cat in chart.active) { + for (var i = 0; i < chart.active[cat].length; i++) { + var currentEdge = chart.active[cat][i]; + if (currentEdge.remLin.length && currentEdge.remLin[0].id == "argProj") { + var argNumber = currentEdge.remLin[0].i; + var catToCombine = currentEdge.args[argNumber]; + if (chart.passive[catToCombine]) { + for (var k = 0, l = chart.passive[catToCombine].length; k < l; k++) { + var currentPassive = chart.passive[catToCombine][k]; + var remLin = currentEdge.remLin.slice(0); + var linRow = currentPassive[remLin[0].label]; + if (typeof linRow != 'undefined') { + var newLinRow = linRow.slice(0); + if (currentEdge.children[argNumber].length == 0) { + var newRange = rangeConcatLin(currentEdge.currLin, newLinRow.shift()); + if (typeof newRange != 'undefined') { + remLin.shift(); + var children = currentEdge.children.slice(0); + children[argNumber] = currentPassive.slice(0); + var newActive = new ActiveEdge(currentEdge.profile, currentEdge.cat, currentEdge.name, currentEdge.args, currentEdge.linFound, currentEdge.currLabel, newRange, remLin, currentEdge.remLinRows, children); + if (!chart.isActiveElem(cat, newActive)) { + chart.active[cat].push(newActive); + chart.updated = true; + } + } + } else { + var child = currentEdge.children[argNumber]; + if (linRecsAreEqual(currentPassive, child)) { + var newRange = rangeConcatLin(currentEdge.currLin, newLinRow.shift()); + if (typeof newRange != 'undefined') { + remLin.shift(); + var children = currentEdge.children.slice(0); + children[argNumber] = currentPassive.slice(0); + var newActive = new ActiveEdge(currentEdge.profile, currentEdge.cat, currentEdge.name, currentEdge.args, currentEdge.linFound, currentEdge.currLabel, newRange, remLin, currentEdge.remLinRows, children); + if (!chart.isActiveElem(cat, newActive)) { + chart.active[cat].push(newActive); + chart.updated = true; + } + } + } + } + } + } + } + } + } + } +} + +// Checks if the parsing goal is in the chart +function foundTarget(cat, linRec) { + if (chart.passive[cat]) { + for (var i = 0, j = chart.passive[cat].length; i < j; i++) { + if (linRecsAreEqual(linRec, chart.passive[cat][i])) { + return true; + } + } + } + return false; +} + +// Filters the active edges that are relevant for tree extraction +function filterActiveEdges() { + var activeEdges = new Array(); + for (var cat in chart.active) { + activeEdges[cat] = new Array(); + for (var i = 0, j = chart.active[cat].length; i < j; i++) { + var currentEdge = chart.active[cat][i]; + if (currentEdge.remLin.length == 0 && currentEdge.remLinRows.length == 0) { + var linFound = currentEdge.linFound.slice(0); + linFound.push(new Array(currentEdge.currLin)); + var newActive = new ActiveEdge(currentEdge.profile, currentEdge.cat, currentEdge.name, currentEdge.args, linFound, "", "", "", "", currentEdge.children); + activeEdges[cat].push(newActive); + } + } + } + return activeEdges; +} + +// Extracts the parse trees from the chart +function extractTrees(cat, linRec, activeEdges, currentTree) { + var trees = new Array(); + for (var i = 0, j = activeEdges[cat].length; i < j; i++) { + var currentEdge = activeEdges[cat][i]; + var currentNode = "(" + cat + "-" + i + ")"; + if (currentTree.indexOf(currentNode) == -1 && cat == currentEdge.cat && linRecsAreEqual(linRec, currentEdge.linFound)) { + var subTrees = new Array(); + for (var k = 0, l = currentEdge.children.length; k < l; k++) { + subTrees.push(extractTrees(currentEdge.args[k], currentEdge.children[k].slice(0), activeEdges, currentTree + currentNode)); + } + var combinedSubTrees = combineLins(subTrees); + if (combinedSubTrees) { + if (currentEdge.children.length == 0) { combinedSubTrees.push(new Array()); } + for (var m = 0, n = combinedSubTrees.length; m < n; m++) { + var tree = buildTree(currentEdge.profile, combinedSubTrees[m]); + if (tree) { + trees.push(tree); + } + } + } + } + } + if (trees.length == 0) { + return undefined; + } else { + return trees; + } +} + +// Builds a tree according to the profile +function buildTree(profile, args) { + switch(profile.id) + { + case "FunApp": + var tree = new Fun(profile.name); + for (var i = 0, j = profile.args.length; i < j; i++) { + var subTree = buildTree(profile.args[i], args); + if (subTree) { + tree.setArg(i, subTree); + } else { + return undefined; + } + } + return tree; + case "Lit": + return new Fun(profile.name); + case "MetaVar": + return new Fun("?"); + case "Arg": + return args[profile.i]; + case "Unify": + var subTrees = new Array(); + for (var i = 0, j = profile.args.length; i < j; i++) { + subTrees.push(buildTree(profile.args[i], args)) + } + return unifySubTrees(subTrees); + } +} + +// Tree unification functions +function unifySubTrees(subTrees) { + var t = subTrees[0]; + for (var i = 1, j = subTrees.length; i < j; i++) { + t = unify(t, subTrees[i]); + if (!t) { return undefined; } + } + return t; +} + +function unify(a, b) { + if (a.isMeta()) { return b }; + if (b.isMeta()) { return a }; + if (a.name == b.name && a.args.length == b.args.length) { + for (var i = 0, j = a.args.length; i < j; i++) { + if (!unify(a.args[i], b.args[i])) { return undefined; } + } + return a + }; + return undefined; +} diff --git a/src/runtime/javascript/grammar.js b/src/runtime/javascript/grammar.js new file mode 100644 index 000000000..69175bba4 --- /dev/null +++ b/src/runtime/javascript/grammar.js @@ -0,0 +1 @@ +var Food = new GFGrammar(new GFAbstract("Phrase",{Boring: new Type([], "Quality"), Cheese: new Type([], "Kind"), Delicious: new Type([], "Quality"), Expensive: new Type([], "Quality"), Fish: new Type([], "Kind"), Fresh: new Type([], "Quality"), Is: new Type(["Item", "Quality"], "Phrase"), Italian: new Type([], "Quality"), QKind: new Type(["Quality", "Kind"], "Kind"), That: new Type(["Kind"], "Item"), This: new Type(["Kind"], "Item"), Very: new Type(["Quality"], "Quality"), Warm: new Type([], "Quality"), Wine: new Type([], "Kind")}),{FoodEng: new GFConcrete({},{Boring: function(cs){return new Arr(new Str("boring"));}, Cheese: function(cs){return new Arr(new Str("cheese"));}, Delicious: function(cs){return new Arr(new Str("delicious"));}, Expensive: function(cs){return new Arr(new Str("expensive"));}, Fish: function(cs){return new Arr(new Str("fish"));}, Fresh: function(cs){return new Arr(new Str("fresh"));}, Is: function(cs){return new Arr(new Seq(cs[0].sel(new Int(0)), new Str("is"), cs[1].sel(new Int(0))));}, Italian: function(cs){return new Arr(new Str("Italian"));}, QKind: function(cs){return new Arr(new Seq(cs[0].sel(new Int(0)), cs[1].sel(new Int(0))));}, That: function(cs){return new Arr(new Seq(new Str("that"), cs[0].sel(new Int(0))));}, This: function(cs){return new Arr(new Seq(new Str("this"), cs[0].sel(new Int(0))));}, Very: function(cs){return new Arr(new Seq(new Str("very"), cs[0].sel(new Int(0))));}, Warm: function(cs){return new Arr(new Str("warm"));}, Wine: function(cs){return new Arr(new Str("wine"));}, Item: function(cs){return new Arr(cs[0]);}, Kind: function(cs){return new Arr(cs[0]);}, Phrase: function(cs){return new Arr(cs[0]);}, Quality: function(cs){return new Arr(cs[0]);}, "Int": function(cs){return new Arr(cs[0]);}, "Float": function(cs){return new Arr(cs[0]);}, "String": function(cs){return new Arr(cs[0]);}}, new Parser("Phrase",[new Rule(1, new FunApp("Boring",[]),[],[[new Terminal("boring")]]), new Rule(1, new FunApp("Delicious",[]),[],[[new Terminal("delicious")]]), new Rule(1, new FunApp("Expensive",[]),[],[[new Terminal("expensive")]]), new Rule(1, new FunApp("Fresh",[]),[],[[new Terminal("fresh")]]), new Rule(1, new FunApp("Italian",[]),[],[[new Terminal("Italian")]]), new Rule(1, new FunApp("Very",[new Arg(0)]),[1],[[new Terminal("very"), new ArgProj(0, 0)]]), new Rule(1, new FunApp("Warm",[]),[],[[new Terminal("warm")]]), new Rule(2, new FunApp("Cheese",[]),[],[[new Terminal("cheese")]]), new Rule(2, new FunApp("Fish",[]),[],[[new Terminal("fish")]]), new Rule(2, new FunApp("QKind",[new Arg(0), new Arg(1)]),[1, 2],[[new ArgProj(0, 0), new ArgProj(1, 0)]]), new Rule(2, new FunApp("Wine",[]),[],[[new Terminal("wine")]]), new Rule(3, new FunApp("Is",[new Arg(0), new Arg(1)]),[4, 1],[[new ArgProj(0, 0), new Terminal("is"), new ArgProj(1, 0)]]), new Rule(4, new FunApp("That",[new Arg(0)]),[2],[[new Terminal("that"), new ArgProj(0, 0)]]), new Rule(4, new FunApp("This",[new Arg(0)]),[2],[[new Terminal("this"), new ArgProj(0, 0)]])],{Float:[-3], Int:[-2], Item:[4], Kind:[2], Phrase:[3], Quality:[1], String:[-1], _Var:[-4]})), FoodIta: new GFConcrete({},{Boring: function(cs){return new Arr(new Str("noioso"));}, Cheese: function(cs){return new Arr(new Str("formaggio"));}, Delicious: function(cs){return new Arr(new Str("delizioso"));}, Expensive: function(cs){return new Arr(new Str("caro"));}, Fish: function(cs){return new Arr(new Str("pesce"));}, Fresh: function(cs){return new Arr(new Str("fresco"));}, Is: function(cs){return new Arr(new Seq(cs[0].sel(new Int(0)), new Str("è"), cs[1].sel(new Int(0))));}, Italian: function(cs){return new Arr(new Str("italiano"));}, QKind: function(cs){return new Arr(new Seq(cs[1].sel(new Int(0)), cs[0].sel(new Int(0))));}, That: function(cs){return new Arr(new Seq(new Str("quel"), cs[0].sel(new Int(0))));}, This: function(cs){return new Arr(new Seq(new Str("questo"), cs[0].sel(new Int(0))));}, Very: function(cs){return new Arr(new Seq(new Str("molto"), cs[0].sel(new Int(0))));}, Warm: function(cs){return new Arr(new Str("caldo"));}, Wine: function(cs){return new Arr(new Str("vino"));}, Item: function(cs){return new Arr(cs[0]);}, Kind: function(cs){return new Arr(cs[0]);}, Phrase: function(cs){return new Arr(cs[0]);}, Quality: function(cs){return new Arr(cs[0]);}, "Int": function(cs){return new Arr(cs[0]);}, "Float": function(cs){return new Arr(cs[0]);}, "String": function(cs){return new Arr(cs[0]);}}, new Parser("Phrase",[new Rule(1, new FunApp("Boring",[]),[],[[new Terminal("noioso")]]), new Rule(1, new FunApp("Delicious",[]),[],[[new Terminal("delizioso")]]), new Rule(1, new FunApp("Expensive",[]),[],[[new Terminal("caro")]]), new Rule(1, new FunApp("Fresh",[]),[],[[new Terminal("fresco")]]), new Rule(1, new FunApp("Italian",[]),[],[[new Terminal("italiano")]]), new Rule(1, new FunApp("Very",[new Arg(0)]),[1],[[new Terminal("molto"), new ArgProj(0, 0)]]), new Rule(1, new FunApp("Warm",[]),[],[[new Terminal("caldo")]]), new Rule(2, new FunApp("Cheese",[]),[],[[new Terminal("formaggio")]]), new Rule(2, new FunApp("Fish",[]),[],[[new Terminal("pesce")]]), new Rule(2, new FunApp("QKind",[new Arg(0), new Arg(1)]),[1, 2],[[new ArgProj(1, 0), new ArgProj(0, 0)]]), new Rule(2, new FunApp("Wine",[]),[],[[new Terminal("vino")]]), new Rule(3, new FunApp("Is",[new Arg(0), new Arg(1)]),[4, 1],[[new ArgProj(0, 0), new Terminal("è"), new ArgProj(1, 0)]]), new Rule(4, new FunApp("That",[new Arg(0)]),[2],[[new Terminal("quel"), new ArgProj(0, 0)]]), new Rule(4, new FunApp("This",[new Arg(0)]),[2],[[new Terminal("questo"), new ArgProj(0, 0)]])],{Float:[-3], Int:[-2], Item:[4], Kind:[2], Phrase:[3], Quality:[1], String:[-1], _Var:[-4]}))}); diff --git a/src/runtime/javascript/minus.png b/src/runtime/javascript/minus.png Binary files differnew file mode 100644 index 000000000..84cc2a9ba --- /dev/null +++ b/src/runtime/javascript/minus.png diff --git a/src/runtime/javascript/plus.png b/src/runtime/javascript/plus.png Binary files differnew file mode 100644 index 000000000..4d2e8ee83 --- /dev/null +++ b/src/runtime/javascript/plus.png diff --git a/src/runtime/javascript/style.css b/src/runtime/javascript/style.css new file mode 100644 index 000000000..962c3701f --- /dev/null +++ b/src/runtime/javascript/style.css @@ -0,0 +1,241 @@ +body {
+ font-family:arial,helvetica,sans-serif;
+ font-size:12px;
+ background-color: white;
+}
+
+#wrapper {
+ width:740px;
+ height:520px;
+ margin:auto 50px;
+ border:1px solid gray;
+ padding:10px;
+
+}
+
+#absFrame {
+ width:250px;
+ height:250px;
+ padding:10px;
+ border:1px solid gray;
+ float:left;
+ white-space: nowrap;
+}
+
+#conFrame {
+ width:436px;
+ height:250px;
+ margin-left:10px;
+ padding:10px;
+ border:1px solid gray;
+ float:left;
+ white-space: normal;
+ overflow:auto;
+}
+
+#actFrame {
+ width:250px;
+ height:170px;
+ margin-top:10px;
+ padding:10px;
+ border:1px solid gray;
+ float:left;
+ overflow:auto;
+}
+
+#refFrame {
+ width:436px;
+ height:170px;
+ margin-left:10px;
+ margin-top:10px;
+ padding:10px;
+ border:1px solid gray;
+ float:left;
+ overflow:auto;
+}
+
+#messageFrame {
+ width:506px;
+ height:15px;
+ margin-top:10px;
+ margin-right:10px;
+ padding:10px;
+ border:1px solid gray;
+ float:left;
+ overflow:hidden;
+}
+
+#clipboardFrame {
+ width:180px;
+ height:15px;
+ margin-top:10px;
+ padding:10px;
+ border:1px solid gray;
+ float:left;
+ overflow:auto;
+}
+
+#tree {
+ left: -10px;
+ top: -10px;
+ width: 250px;
+ height: 250px;
+ margin: 0px;
+ padding: 10px;
+ overflow: auto;
+}
+
+ul {
+ position: relative;
+ list-style: none;
+ margin-left: 20px;
+ padding: 0px;
+}
+
+li {
+ position: relative;
+}
+
+img.tree-menu {
+ margin-right: 5px;
+}
+
+a.tree:link, a.tree:visited, a.tree:active {
+ color: black;
+ background-color: white;
+ text-decoration: none;
+ margin-right:10px;
+}
+
+a.tree:hover {
+ color: blue;
+ background-color: white;
+ text-decoration: underline;
+ margin-right:10px;
+}
+
+a.treeSelected:link, a.treeSelected:visited, a.treeSelected:active {
+ color: white;
+ background-color: #3366CC;
+ text-decoration: none;
+ margin-right:10px;
+}
+
+a.treeSelected:hover {
+ color: white;
+ background-color: #3366CC;
+ text-decoration: underline;
+ margin-right:10px;
+}
+
+a.treeGray:link, a.treeGray:visited, a.treeGray:active {
+ color: silver;
+ background-color: white;
+ text-decoration: none;
+ margin-right:10px;
+}
+
+a.treeGray:hover {
+ color: silver;
+ background-color: white;
+ text-decoration: none;
+ margin-right:10px;
+}
+
+table.action, table.refinement, table.wrapper, table.tree, table.language {
+ margin: 0px;
+ padding: 0px;
+ border-style: none;
+ border-collapse: collapse;
+ border-spacing: 0px;
+}
+
+tr.selected {
+ color: white;
+ background-color: #3366CC;
+}
+
+tr.unavailable, tr.closed {
+ color: silver;
+ background-color: white;
+}
+
+tr.unavailable:hover {
+ color: silver;
+ background-color: #3366CC;
+}
+
+tr.action, tr.refinement, tr.wrapper, tr.tree {
+ color: black;
+ background-color: white;
+}
+
+tr.action:hover, tr.refinement:hover, tr.wrapper:hover, tr.tree:hover {
+ color: white;
+ background-color: #3366CC;
+}
+
+td.action {
+ width: 220px;
+ margin: 0px;
+ padding: 0px;
+}
+
+td.refinement, td.wrapper, td.tree {
+ width: 515px;
+ margin: 0px;
+ padding: 0px;
+}
+
+td.hotKey {
+ width: 30px;
+ margin: 0px;
+ padding: 0px;
+ text-align: right;
+}
+
+td.language {
+ color: black;
+ background-color: white;
+ margin: 1px;
+ padding: 1px;
+}
+
+td.language:hover {
+ color: blue;
+ background-color: white;
+ text-decoration: underline;
+ margin: 1px;
+ padding: 1px;
+}
+
+td.selected {
+ color: white;
+ background-color: #3366CC;
+ margin: 1px;
+ padding: 1px;
+}
+
+td.selected:hover {
+ color: white;
+ background-color: #3366CC;
+ text-decoration: underline;
+ margin: 1px;
+ padding: 1px;
+}
+
+p {
+ margin-bottom: 40px;
+}
+
+span.normal {
+ color: black;
+ background-color: white;
+ text-decoration: none;
+}
+
+span.selected {
+ color: white;
+ background-color: #3366CC;
+ text-decoration: none;
+}
diff --git a/src/runtime/javascript/translator.css b/src/runtime/javascript/translator.css new file mode 100644 index 000000000..f7f771927 --- /dev/null +++ b/src/runtime/javascript/translator.css @@ -0,0 +1,54 @@ +body { + color: black; + background-color: white; +} + +dl { + +} + +dt { + margin: 0; + padding: 0; +} + +dl dd { + margin: 0; + padding: 0; +} + +dl.fromLang dt { + display: none; +} + +dl.toLang { + border-width: 1px 0 0 0; + border-style: solid; + border-color: #c0c0c0; +} + +dl.toLang dt { + color: #c0c0c0; + display: block; + float: left; + width: 5em; +} + + +dl.toLang dd { + border-width: 0 0 1px 0; + border-style: solid; + border-color: #c0c0c0; +} + + +ul { + margin: 0; + padding: 0; +} + +li { + list-style-type: none; + margin: 0; + padding: 0; +}
\ No newline at end of file diff --git a/src/runtime/javascript/translator.html b/src/runtime/javascript/translator.html new file mode 100644 index 000000000..b6fd37086 --- /dev/null +++ b/src/runtime/javascript/translator.html @@ -0,0 +1,48 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <link rel="stylesheet" type="text/css" href="translator.css" /> + <script type="text/javascript" src="gflib.js"></script> + <script type="text/javascript" src="grammar.js"></script> + <script type="text/javascript" src="translator.js"></script> + <script type="text/javascript"> + /* CHANGE ME */ + var grammar = Food; + + function updateTranslation () { + var input = document.getElementById('inputText').value; + var fromLang = document.getElementById('fromLang').value; + var toLang = document.getElementById('toLang').value; + var output = document.getElementById('output'); + var translation = grammar.translate(input, fromLang, toLang); + removeChildren(output); + output.appendChild(formatTranslation(translation)); + } + + function populateLangs () { + var f = document.getElementById('fromLang'); + var t = document.getElementById('toLang'); + for (var c in grammar.concretes) { + addOption(f, c, c); + addOption(t, c, c); + } + } + </script> + <title>Web-based GF Translator</title> + </head> + <body onload="populateLangs(Food, 'fromLang', 'toLang')"> + <form id="translate"> + <p> + <input type="text" name="inputText" id="inputText" value="this cheese is warm" size="50" /> + </p> + <p> + From: <select name="fromLang" id="fromLang" onchange=""><option value="">Any language</option></select> + To: <select name="toLang" id="toLang"><option value="">All languages</option></select> + <input type="button" value="Translate" onclick="updateTranslation()" /> + </p> + </form> + <div id="output"></div> + </body> +</html> diff --git a/src/runtime/javascript/translator.js b/src/runtime/javascript/translator.js new file mode 100644 index 000000000..31da04290 --- /dev/null +++ b/src/runtime/javascript/translator.js @@ -0,0 +1,51 @@ +function formatTranslation (outputs) { + var dl1 = document.createElement("dl"); + dl1.className = "fromLang"; + for (var fromLang in outputs) { + var ul = document.createElement("ul"); + addDefinition(dl1, document.createTextNode(fromLang), ul); + for (var i in outputs[fromLang]) { + var dl2 = document.createElement("dl"); + dl2.className = "toLang"; + for (var toLang in outputs[fromLang][i]) { + addDefinition(dl2, document.createTextNode(toLang), document.createTextNode(outputs[fromLang][i][toLang])); + } + addItem(ul, dl2); + } + } + + return dl1; +} + +/* DOM utilities for specific tags */ + +function addDefinition (dl, t, d) { + var dt = document.createElement("dt"); + dt.appendChild(t); + dl.appendChild(dt); + var dd = document.createElement("dd"); + dd.appendChild(d); + dl.appendChild(dd); +} + +function addItem (ul, i) { + var li = document.createElement("li"); + li.appendChild(i); + ul.appendChild(li); +} + +function addOption (select, value, content) { + var option = document.createElement("option"); + option.value = value; + option.appendChild(document.createTextNode(content)); + select.appendChild(option); +} + +/* General DOM utilities */ + +/* Removes all the children of a node */ +function removeChildren(node) { + while (node.hasChildNodes()) { + node.removeChild(node.firstChild); + } +} |
