git @ Cat's Eye Technologies Fountain / d6ce9d0
Merge branch 'develop-0.6' into convert-loops-to-recursion Chris Pressey 1 year, 2 months ago
6 changed file(s) with 55 addition(s) and 85 deletion(s). Raw diff Collapse all Expand all
380380
381381 Goal ::= "a" { "bb" } "c" | "a" { "bbb" } "c";
382382 <=== abbbbbbbbbc
383 ???> Multiple pre-conditions
383 ???> Multiple
384384
385385 Tests for Generation
386386 --------------------
396396 unlike parsing, we need some guidance of which one to pick.
397397
398398 Goal ::= "f" | "o";
399 ???> No pre-condition
399 ???> Multiple
400400
401401 Goal ::= "f" | <. a = 0 .> "o";
402 ???> No pre-condition
402 ???> Multiple
403403
404404 Goal ::= (<. a = 0 .> "f") | "o";
405 ???> No pre-condition
405 ???> Multiple
406406
407407 But if all choices of the Alt have constraints, we are able to select the one
408408 that fulfills the constraints.
418418 that is an ambiguous situation, and (in normal operation) it is an error.
419419
420420 Goal ::= <. a = 0 .> "f" | <. a = 1 .> "o";
421 ???> Multiple pre-conditions
421 ???> Multiple
422422
423423 Goal ::= <. a = 0 .> (<. a = 0 .> "f" | <. a = 1 .> "o") (<. a = 1 .> "a" | <. a = 0 .> "z");
424424 ===> fz
582582 | "ooooo" <. a += 5 .> <. a <= n .> Item<a, n>
583583 | "xxxxxxx" <. a += 7 .> <. a <= n .> Item<a, n>;
584584 <=== n=6
585 ???> No pre-condition
585 ???> Multiple
586586
587587 The alternation processed as ordered choice, above, can also be
588588 processed with nondeterministic choice. In this case, the process
1212 | ConVal a
1313 deriving (Show, Ord, Eq)
1414
15 data Constraint a = Unify Variable (ConExpr a)
15 data Constraint a = Identity
16 | Unify Variable (ConExpr a)
1617 | Inc Variable (ConExpr a)
1718 | Dec Variable (ConExpr a)
1819 | GreaterThan Variable (ConExpr a)
2930 depictConExpr (ConVar v) = depictVar v
3031 depictConExpr (ConVal i) = show i
3132
33 depictConstraint Identity = "T"
3234 depictConstraint (Unify v e) = (depictVar v) ++ " = " ++ (depictConExpr e)
3335 depictConstraint (Inc v e) = (depictVar v) ++ " += " ++ (depictConExpr e)
3436 depictConstraint (Dec v e) = (depictVar v) ++ " -= " ++ (depictConExpr e)
33
44 module Language.Fountain.Generator (constructState, generateFrom, obtainResult) where
55
6 import Data.Maybe (mapMaybe)
76 import System.Random (StdGen, mkStdGen)
87
98 import Language.Fountain.Randomness (shuffle)
3736 genTerminal :: Char -> GenState -> GenState
3837 genTerminal c state@Generating{ text=text } = state{ text=(c:text) }
3938
40 --
41 -- Alt choices need preconditions during generation because
42 -- we need some guidance of which one to pick.
43 --
44 getPreCondition :: Expr -> Maybe (Constraint Value)
45 getPreCondition (Seq (x:_)) = getPreCondition x
46 getPreCondition (Constraint c) = Just c
47 getPreCondition _ = Nothing
48
49 missingPreConditions choices =
50 mapMaybe (\x -> case getPreCondition x of
51 Just _ -> Nothing
52 Nothing -> Just x
53 ) choices
54
55 getApplicableChoices store choices =
39 getApplicableChoices state choices =
5640 let
5741 preConditionedChoices = map (\x -> (getPreCondition x, x)) choices
58 isApplicableChoice (Just c, _) = can $ applyConstraint c store
59 isApplicableChoice _ = False
42 isApplicableChoice (c, _) = can $ applyGenConstraint c state
6043 in
6144 filter (isApplicableChoice) preConditionedChoices
45
46 applyGenConstraint :: Constraint Value -> Store Value -> Maybe (Store Value)
47 applyGenConstraint (Lookahead _) store = Just store
48 applyGenConstraint other store = applyConstraint other store
6249
6350 scramble :: [a] -> GenState -> ([a], GenState)
6451 scramble choices state@Generating{ prng=prng } =
10188 -- We look at all the choices; each should start with a pre-condition
10289 -- determining whether we can select it; and we should narrow down our
10390 -- choices based on that.
104 case missingPreConditions choices of
105 missing@(_:_) ->
106 error ("No pre-condition present on these Alt choices: " ++ (depictExprs missing))
107 [] ->
108 genAlt state (getApplicableChoices store choices)
109 where
110 genAlt _st [] = Left "no more choices"
111 -- we ignore the constraint here because it will be found and applied when we descend into e
112 genAlt st [(_, e)] = gen g st e
113 genAlt _st other =
114 error ("Multiple pre-conditions are satisfied in Alt: " ++ (depictExprs (map (snd) other)))
91 genAlt state (getApplicableChoices store choices)
92 where
93 genAlt _st [] = Left "no more choices"
94 -- we ignore the constraint here because it will be found and applied when we descend into e
95 genAlt st [(_, e)] = gen g st e
96 genAlt _st other =
97 error ("Multiple pre-conditions are satisfied in Alt: " ++ (depictExprs (map (snd) other)))
11598
11699
117100 gen _g _state (Loop _ []) = error "No postconditions defined for this Loop"
131114 Nothing -> genLoop st' e
132115 checkLimit [] st = Just st
133116 checkLimit (c:cs) st =
134 case applyConstraint c st of
117 case applyGenConstraint c st of
135118 Nothing -> Nothing
136119 Just st' -> checkLimit cs st'
137120
151134 Left x
152135
153136 gen _g st@Generating{ store=store } (Constraint cstr) =
154 case applyConstraint cstr store of
137 case applyGenConstraint cstr store of
155138 Just store' ->
156139 -- TODO st{ trace=(("OK " ++ depictConstraint cstr):trace), store=store' }
157140 Right $ st{ store=store' }
88 Production(Production, ntname, params, backtrackMode, constituents),
99 Grammar(Grammar),
1010 depictExpr, depictExprs, depictProduction, depictGrammar, depictVars,
11 startSymbol, productionExpr, productionParams, getFormals, mergeGrammars
11 startSymbol, productionExpr, productionParams, getFormals, mergeGrammars,
12 getPreCondition
1213 ) where
1314
1415 import Data.List (intercalate)
9495
9596 mergeGrammars :: Grammar -> Grammar -> Grammar
9697 mergeGrammars (Grammar ps1) (Grammar ps2) = Grammar $ ps1 ++ ps2
98
99 --
100 -- Alt choices heed preconditions to prevent unnecessary backtracking.
101 --
102 getPreCondition :: Expr -> Constraint Value
103 getPreCondition (Seq (x:_)) = getPreCondition x
104 getPreCondition (Constraint c) = c
105 getPreCondition (Terminal c) = Lookahead s where s = [c]
106 getPreCondition _ = Identity
22 -- SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Fountain
33
44 module Language.Fountain.Parser (constructState, parseFrom, obtainResult) where
5
6 import Data.Maybe (mapMaybe)
75
86 import Language.Fountain.Value
97 import Language.Fountain.Constraint
3230 expectTerminal _tc (Parsing [] _a) =
3331 Left "end of string"
3432
35 --
36 -- Alt choices need preconditions during parsing because it helps
37 -- efficiency by preventing unnecessary backtracking. But note that
38 -- we need a more refined notion in parsing than in generation,
39 -- because a terminal counts as a precondition.
40 --
41 getPreCondition :: Expr -> Maybe (Constraint Value)
42 getPreCondition (Seq (x:_)) = getPreCondition x
43 getPreCondition (Constraint c) = Just c
44 getPreCondition (Terminal c) = Just $ Lookahead s where s = [c]
45 getPreCondition _ = Nothing
46
47 missingPreConditions choices =
48 mapMaybe (\x -> case getPreCondition x of
49 Just _ -> Nothing
50 Nothing -> Just x
51 ) choices
52
5333 getApplicableChoices state choices =
5434 let
5535 preConditionedChoices = map (\x -> (getPreCondition x, x)) choices
56 isApplicableChoice (Just c, _) = can $ applyParseConstraint c state
57 isApplicableChoice _ = False
36 isApplicableChoice (c, _) = can $ applyParseConstraint c state
5837 in
5938 filter (isApplicableChoice) preConditionedChoices
39
40 applyParseConstraint :: Constraint Value -> ParseState -> ParseResult
41 applyParseConstraint (Lookahead s) state@(Parsing (c:_) _) =
42 if s == [c] then (Right state) else (Left "lookahead failed")
43 applyParseConstraint (Lookahead _) _ = Left "lookahead failed"
44 applyParseConstraint other (Parsing s store) =
45 case applyConstraint other store of
46 Just store' ->
47 Right $ Parsing s store'
48 Nothing ->
49 Left "constraint failed"
6050
6151 --
6252 -- Parser
8373
8474 -- Hello, Mrs Non-Backtracking Alternation!
8575 parse g state (Alt Nothing choices) =
86 case missingPreConditions choices of
87 missing@(_:_) ->
88 error ("No pre-condition present on these Alt choices: " ++ (depictExprs missing))
89 [] ->
90 parseAlt state (getApplicableChoices state choices)
91 where
92 parseAlt _st [] = Left "no more choices"
93 -- we ignore the constraint here because it will be found and applied when we descend into e
94 parseAlt st [(_, e)] = parse g st e
95 parseAlt (Parsing _str store) other =
96 error ("Multiple pre-conditions are satisfied in Alt: " ++ (depictExprs (map (snd) other)) ++ ", with state: " ++ show store)
76 parseAlt state (getApplicableChoices state choices)
77 where
78 parseAlt _st [] = Left "no more choices"
79 -- we ignore the constraint here because it will be found and applied when we descend into e
80 parseAlt st [(_, e)] = parse g st e
81 parseAlt (Parsing _str store) other =
82 error ("Multiple pre-conditions are satisfied in Alt: " ++ (depictExprs (map (snd) other)) ++ ", with state: " ++ show store)
9783
9884 parse g state (Loop l []) = parseLoop state l where
9985 parseLoop st e =
123109
124110 parse _g state (Constraint cstr) = applyParseConstraint cstr state
125111
126
127 applyParseConstraint :: Constraint Value -> ParseState -> ParseResult
128 applyParseConstraint (Lookahead s) state@(Parsing (c:_) _) =
129 if s == [c] then (Right state) else (Left "lookahead failed")
130 applyParseConstraint (Lookahead _) _ = Left "lookahead failed"
131 applyParseConstraint other (Parsing s store) =
132 case applyConstraint other store of
133 Just store' ->
134 Right $ Parsing s store'
135 Nothing ->
136 Left "constraint failed"
137
138112 --
139113 -- Usage interface
140114 --
2222 -- (by unification, causing the constraint to become true.)
2323 --
2424 applyConstraint :: Constraint Value -> Store Value -> Maybe (Store Value)
25 applyConstraint Identity st = Just st
2526 applyConstraint (Unify v (ConVal x)) st =
2627 case fetch v st of
2728 Just value ->