mida-1.0.2: src/Mida/Language/SyntaxTree.hs
--
-- This module defines abstract syntax tree of MIDA language.
--
-- Copyright © 2014–2016 Mark Karpov
--
-- MIDA is free software: you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- MIDA is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-- details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program. If not, see <http://www.gnu.org/licenses/>.
module Mida.Language.SyntaxTree
( SyntaxTree
, Sel (..)
, Statement (..) )
where
import Data.Char (isLetter, isAlphaNum)
import Data.List.NonEmpty (NonEmpty (..))
import Numeric.Natural
import Test.QuickCheck
-- | Syntax tree in our case is just a collection of syntactic elements.
type SyntaxTree = [Sel]
-- | Syntactic element corresponds to language tokens. Some of them have
-- direct corresponding constructor in 'Mida.Language.Element.Element',
-- others have to be simplified first.
data Sel
= Value Natural -- ^ Literal value
| Section [Sel] -- ^ Section
| Multi [Sel] -- ^ Multivalue
| CMulti (NonEmpty ([Sel], [Sel])) -- ^ Conditional multivalue
| Reference String -- ^ Reference (name of variable)
| Range Natural Natural -- ^ Range of values
| Product Sel Sel -- ^ Product of principles
| Division Sel Sel -- ^ Division of principles
| Sum Sel Sel -- ^ Sum of principles
| Diff Sel Sel -- ^ Subtraction of principles
| Loop Sel Sel -- ^ Loop
| Rotation Sel Sel -- ^ Rotation
| Reverse Sel -- ^ Reversed principle
deriving (Eq, Show)
instance Arbitrary Sel where
arbitrary = sized arbitrarySel
arbitrarySel :: Int -> Gen Sel
arbitrarySel 0 =
oneof [ Value <$> nonNegative
, Reference <$> identifier
, Range <$> nonNegative <*> nonNegative ]
where nonNegative = getNonNegative <$> arbitrary
arbitrarySel n =
oneof [ Section <$> listSel
, Multi <$> listSel
, CMulti <$> listCnd
, Product <$> leafSel <*> leafSel
, Division <$> leafSel <*> leafSel
, Sum <$> leafSel <*> leafSel
, Diff <$> leafSel <*> leafSel
, Loop <$> leafSel <*> leafSel
, Rotation <$> leafSel <*> leafSel
, Reverse <$> leafSel ]
where cnSel d = arbitrarySel (n `div` d)
vcSel d = listOf (cnSel $ d * 20)
leafSel = cnSel 10
listSel = vcSel 20
listCnd =
let x = (,) <$> vcSel 25 <*> vcSel 25
in (:|) <$> x <*> listOf x
-- | Statement can be either definition or exposition. Expositions are only
-- used in REPL.
data Statement
= Definition String SyntaxTree
| Exposition SyntaxTree
deriving (Eq, Show)
instance Arbitrary Statement where
arbitrary =
oneof [ Definition <$> identifier <*> arbitrary
, Exposition <$> arbitrary ]
----------------------------------------------------------------------------
-- Helpers
identifier :: Gen String
identifier = (:) <$> ch0 <*> chN
where ch0 = u isLetter
chN = listOf $ u isAlphaNum
u f = frequency [(1, return '_'), (74, arbitrary `suchThat` f)]