zenlish 0.1.25 → 0.2.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -1
- data/LICENSE.txt +1 -1
- data/README.md +3 -3
- data/lib/zenlish/feature/boolean_domain.rb +29 -0
- data/lib/zenlish/feature/boolean_value.rb +9 -0
- data/lib/zenlish/feature/enumeration_domain.rb +32 -0
- data/lib/zenlish/feature/feature.rb +30 -0
- data/lib/zenlish/feature/feature_def.rb +48 -0
- data/lib/zenlish/feature/feature_domain.rb +9 -0
- data/lib/zenlish/feature/feature_struct.rb +24 -0
- data/lib/zenlish/feature/feature_struct_def.rb +44 -0
- data/lib/zenlish/feature/feature_struct_def_bearer.rb +65 -0
- data/lib/zenlish/feature/feature_value.rb +17 -0
- data/lib/zenlish/feature/identifier_domain.rb +29 -0
- data/lib/zenlish/feature/identifier_value.rb +9 -0
- data/lib/zenlish/feature/symbol_value.rb +8 -0
- data/lib/zenlish/inflect/atomic_o_expression.rb +9 -0
- data/lib/zenlish/inflect/composite_o_expression.rb +14 -0
- data/lib/zenlish/inflect/concatenation.rb +36 -0
- data/lib/zenlish/inflect/equals_literal.rb +25 -0
- data/lib/zenlish/inflect/feature_heading.rb +16 -0
- data/lib/zenlish/inflect/formal_argument.rb +11 -0
- data/lib/zenlish/inflect/heading.rb +11 -0
- data/lib/zenlish/inflect/inflection_rule.rb +28 -0
- data/lib/zenlish/inflect/inflection_table.rb +46 -0
- data/lib/zenlish/inflect/inflection_table_builder.rb +120 -0
- data/lib/zenlish/inflect/input_asis.rb +22 -0
- data/lib/zenlish/inflect/input_expression.rb +9 -0
- data/lib/zenlish/inflect/literal_asis.rb +17 -0
- data/lib/zenlish/inflect/matches_pattern.rb +26 -0
- data/lib/zenlish/inflect/method_heading.rb +16 -0
- data/lib/zenlish/inflect/nullary_input_expression.rb +8 -0
- data/lib/zenlish/inflect/output_expression.rb +6 -0
- data/lib/zenlish/inflect/substitution.rb +65 -0
- data/lib/zenlish/inflect/unary_input_expression.rb +13 -0
- data/lib/zenlish/inflect/unconditionally_true.rb +11 -0
- data/lib/zenlish/lang/dictionary.rb +19 -6
- data/lib/zenlish/lang/zenlish_grammar.rb +1 -0
- data/lib/zenlish/lex/empty_lexicon_factory.rb +3 -0
- data/lib/zenlish/lex/lexeme.rb +27 -4
- data/lib/zenlish/lex/lexicon.rb +3 -0
- data/lib/zenlish/lex/literal.rb +5 -1
- data/lib/zenlish/version.rb +1 -1
- data/lib/zenlish/wclasses/common_noun.rb +45 -0
- data/lib/zenlish/wclasses/noun.rb +21 -0
- data/lib/zenlish/wclasses/preposition.rb +5 -0
- data/lib/zenlish/wclasses/proper_noun.rb +11 -0
- data/lib/zenlish/wclasses/verb.rb +9 -1
- data/lib/zenlish/wclasses/word_class.rb +21 -6
- data/spec/spec_helper.rb +2 -3
- data/spec/zenlish/feature/boolean_domain_spec.rb +35 -0
- data/spec/zenlish/feature/boolean_value_spec.rb +26 -0
- data/spec/zenlish/feature/enumeration_domain_spec.rb +42 -0
- data/spec/zenlish/feature/feature_def_spec.rb +50 -0
- data/spec/zenlish/feature/feature_spec.rb +51 -0
- data/spec/zenlish/feature/feature_struct_def_bearer_spec.rb +54 -0
- data/spec/zenlish/feature/feature_struct_def_spec.rb +69 -0
- data/spec/zenlish/feature/identifier_domain_spec.rb +36 -0
- data/spec/zenlish/feature/identifier_value_spec.rb +26 -0
- data/spec/zenlish/feature/symbol_value_spec.rb +27 -0
- data/spec/zenlish/inflect/concatenation_spec.rb +40 -0
- data/spec/zenlish/inflect/equals_literal_spec.rb +58 -0
- data/spec/zenlish/inflect/feature_heading_spec.rb +30 -0
- data/spec/zenlish/inflect/formal_argument_spec.rb +25 -0
- data/spec/zenlish/inflect/inflection_rule_spec.rb +102 -0
- data/spec/zenlish/inflect/inflection_table_builder_spec.rb +127 -0
- data/spec/zenlish/inflect/inflection_table_spec.rb +129 -0
- data/spec/zenlish/inflect/input_asis_spec.rb +50 -0
- data/spec/zenlish/inflect/literal_asis_spec.rb +31 -0
- data/spec/zenlish/inflect/matches_pattern_spec.rb +61 -0
- data/spec/zenlish/inflect/method_heading_spec.rb +31 -0
- data/spec/zenlish/inflect/substitution_spec.rb +43 -0
- data/spec/zenlish/inflect/unconditionally_true_spec.rb +28 -0
- data/spec/zenlish/lang/dictionary_spec.rb +33 -0
- data/spec/zenlish/lex/lexeme_spec.rb +24 -9
- data/spec/zenlish/lex/literal_spec.rb +3 -11
- data/spec/zenlish/parser/lesson3_spec.rb +44 -0
- data/spec/zenlish/support/minimal_lexicon.rb +0 -2
- data/spec/zenlish/support/var2word.rb +5 -1
- data/spec/zenlish/wclasses/common_noun_spec.rb +25 -4
- data/spec/zenlish/wclasses/noun_spec.rb +31 -0
- data/spec/zenlish/wclasses/preposition_spec.rb +24 -0
- data/spec/zenlish/wclasses/verb_spec.rb +24 -0
- metadata +89 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68fb4d0914b284ffab37ba5f91c325918bcfaa4948adea0a747297e325c93fe6
|
4
|
+
data.tar.gz: e83dd3b97f088defef045fb01d5d6a7be202f02d4c45e85cdce3f2f718cf9ef2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3de436eaced4062aade3ca3dc2d94915c284c2b38a5775ba3d6880d676cc8d0e3773a244eb1086ddca93f71c265f494b548fb114e7c30ea3b52ad1dbb8694a19
|
7
|
+
data.tar.gz: 7f55f80aad57993fcd1cadf75721f5f53fbd91fa8de6f620fb39fecd70892373dc69fe66fc3d13f43b272096aaf1c5afed60453ac126fb7c03fe9f0a1e435beb
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,26 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## [0.2.00] - 2020-01-30
|
4
|
+
A lot of internal additions, such an initial feature model, embryonic inflection model.
|
5
|
+
This is WIP.
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- New subfolder `feature` that hosts classes for implementing features (= properties that can be attached to words)
|
9
|
+
- New subfolder `inflect` that hosts classes for implmenting inflection tables (kind of decision tables)
|
10
|
+
### Changed
|
11
|
+
- File `dictionary.rb`: new entries in lexicon `damage`, `difficult`
|
12
|
+
- File `dictionary.rb`: common nouns with special inflection rules (e.g. pluralized form) have their paradigm specified
|
13
|
+
- Class `Lexeme` can have its own set of feature definitions.
|
14
|
+
- Class `WordClass` ca have its own set of feature definitions.
|
15
|
+
- Class `Noun` has the feature definitions for: `NUMBER`, `COUNTABILITY` and `PARADIGM`
|
16
|
+
|
17
|
+
|
18
|
+
|
3
19
|
## [0.1.25] - 2019-12-06
|
4
20
|
__Zenlish__ can parse all sentences in lesson 1, 2 and 3-A .. 3-G (352 sentences in total) from
|
5
21
|
[Learn These Words First](http://learnthesewordsfirst.com/).
|
6
22
|
|
7
|
-
|
23
|
+
### Changed
|
8
24
|
- File `lesson3_spec.rb`: tests include all sentences from lesson 3-A to 3-G.
|
9
25
|
- `ZenlishGrammar`: refactoring of the predicative_sentence rules.
|
10
26
|
- File `dictionary.rb`: new entries in lexicon `between`, `choose`, `machine`.
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -33,14 +33,14 @@ Over time, the zenlish gem will contain:
|
|
33
33
|
- A lexicon [STARTED]
|
34
34
|
- A context-free grammar [STARTED]
|
35
35
|
- A parser [STARTED]
|
36
|
-
- Feature unification (for number, gender agreement,...)[
|
36
|
+
- Feature unification (for number, gender agreement,...)[STARTED]
|
37
37
|
- A simplified ontology[TODO]
|
38
38
|
|
39
39
|
|
40
|
-
#### Some project metrics (v. 0.
|
40
|
+
#### Some project metrics (v. 0.2.00)
|
41
41
|
|Metric|Value|
|
42
42
|
|:-:|:-:|
|
43
|
-
| Number of lemmas in dictionary |
|
43
|
+
| Number of lemmas in dictionary | 141 |
|
44
44
|
| [Coverage 100 commonest English words](https://en.wikipedia.org/wiki/Most_common_words_in_English) | 61% |
|
45
45
|
| Number of production rules in grammar | 185 |
|
46
46
|
| Number of lessons covered | 23 |
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require_relative 'feature_domain'
|
3
|
+
require_relative 'boolean_value'
|
4
|
+
|
5
|
+
module Zenlish
|
6
|
+
module Feature
|
7
|
+
class BooleanDomain < FeatureDomain
|
8
|
+
include Singleton # Use the Singleton design patttern
|
9
|
+
|
10
|
+
def build_value(aValue)
|
11
|
+
BooleanValue.new(validated_value(aValue))
|
12
|
+
end
|
13
|
+
|
14
|
+
def include?(aValue)
|
15
|
+
aValue.kind_of?(TrueClass) || aValue.kind_of?(FalseClass)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def validated_value(aValue)
|
21
|
+
if not aValue.is_a?(FalseClass) and not aValue.is_a?(TrueClass)
|
22
|
+
raise StandardError, "Expected a boolean instead of #{aValue.class}."
|
23
|
+
end
|
24
|
+
|
25
|
+
aValue
|
26
|
+
end
|
27
|
+
end # class
|
28
|
+
end # module
|
29
|
+
end # module
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'feature_domain'
|
2
|
+
require_relative 'symbol_value'
|
3
|
+
|
4
|
+
module Zenlish
|
5
|
+
module Feature
|
6
|
+
class EnumerationDomain < FeatureDomain
|
7
|
+
attr_reader :enum
|
8
|
+
|
9
|
+
def initialize(*symbols)
|
10
|
+
@enum = symbols
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_value(aValue)
|
14
|
+
SymbolValue.new(validated_value(aValue))
|
15
|
+
end
|
16
|
+
|
17
|
+
def include?(aValue)
|
18
|
+
enum.include?(aValue)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def validated_value(aValue)
|
24
|
+
unless include?(aValue)
|
25
|
+
raise StandardError, "#{aValue} isn't part of enumeration [#{enum.join(', ')}]."
|
26
|
+
end
|
27
|
+
|
28
|
+
aValue
|
29
|
+
end
|
30
|
+
end # class
|
31
|
+
end # module
|
32
|
+
end # module
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Zenlish
|
4
|
+
module Feature
|
5
|
+
class Feature
|
6
|
+
# Forwardable mix-in module to implement delegation of specified methods.
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# The feature definition
|
10
|
+
attr_reader :definition
|
11
|
+
|
12
|
+
attr_reader :binding
|
13
|
+
|
14
|
+
def_delegators :@definition, :name, :domain
|
15
|
+
|
16
|
+
# @param aDefinition [FeatureDef]
|
17
|
+
def initialize(aDefinition)
|
18
|
+
@definition = aDefinition
|
19
|
+
end
|
20
|
+
|
21
|
+
def bound?
|
22
|
+
not binding.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def bind_to(aFeatureValue)
|
26
|
+
@binding = aFeatureValue
|
27
|
+
end
|
28
|
+
end # class
|
29
|
+
end # module
|
30
|
+
end # module
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative 'enumeration_domain'
|
2
|
+
require_relative 'feature_value'
|
3
|
+
|
4
|
+
module Zenlish
|
5
|
+
module Feature
|
6
|
+
class FeatureDef
|
7
|
+
# @return [String] the name of the feature
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# @return [FeatureDomain] the set of potential values the feature can take
|
11
|
+
attr_reader :domain
|
12
|
+
|
13
|
+
# @return [FeatureValue] the default value for the feature.
|
14
|
+
attr_reader :default
|
15
|
+
|
16
|
+
# @param aName [String] the name of the feature
|
17
|
+
# @param aDomain [FeatureDomain]
|
18
|
+
# @param aDefault [FeatureValue, NilClass]
|
19
|
+
def initialize(aName, aDomain, aDefault = nil)
|
20
|
+
@name = validated_name(aName)
|
21
|
+
@domain = aDomain
|
22
|
+
@default = validated_default(domain, aDefault)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def validated_name(aName)
|
28
|
+
raise StandardError, 'feature name cannot be empty.' if aName.empty?
|
29
|
+
aName.dup
|
30
|
+
end
|
31
|
+
|
32
|
+
def validated_default(aDomain, aDefault)
|
33
|
+
if aDefault
|
34
|
+
default = aDefault
|
35
|
+
elsif aDomain.is_a?(BooleanDomain)
|
36
|
+
default = nil
|
37
|
+
else aDomain.is_a?(EnumerationDomain)
|
38
|
+
if aDomain.enum.size == 1
|
39
|
+
val = FeatureValue.new(aDomain.enum[0])
|
40
|
+
default = val
|
41
|
+
else
|
42
|
+
default = nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end # class
|
47
|
+
end # module
|
48
|
+
end # module
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'feature_value'
|
2
|
+
require_relative 'feature'
|
3
|
+
|
4
|
+
module Zenlish
|
5
|
+
module Feature
|
6
|
+
class FeatureStruct < FeatureValue
|
7
|
+
def initialize(aStructDef)
|
8
|
+
featrs = build_features(aStructDef)
|
9
|
+
super(aStructDef, featrs)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def build_features(aStructDef)
|
15
|
+
feats = []
|
16
|
+
aStructDef.struct.each_value do |feature_def|
|
17
|
+
feats << Feature.new(feature_def)
|
18
|
+
end
|
19
|
+
|
20
|
+
feats
|
21
|
+
end
|
22
|
+
end # class
|
23
|
+
end # module
|
24
|
+
end # module
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative 'feature_domain'
|
2
|
+
|
3
|
+
module Zenlish
|
4
|
+
module Feature
|
5
|
+
class FeatureStructDef < FeatureDomain
|
6
|
+
attr_reader :parent
|
7
|
+
attr_reader :struct
|
8
|
+
|
9
|
+
# @param aParent [FeatureStructDef]
|
10
|
+
def initialize(aParent = nil)
|
11
|
+
@parent = validated_parent(aParent)
|
12
|
+
@struct = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param aFeatureName [String]
|
16
|
+
def [](aFeatureName)
|
17
|
+
return struct[aFeatureName] if struct.include? aFeatureName
|
18
|
+
if parent
|
19
|
+
p_struct = parent.struct
|
20
|
+
return p_struct[aFeatureName] if p_struct.include? aFeatureName
|
21
|
+
end
|
22
|
+
|
23
|
+
raise StandardError, "Unknown feature name #{aFeatureName}"
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param aFeatureDef [Zenlish::Feature::FeatureDef]
|
27
|
+
def add_feature_def(aFeatureDef)
|
28
|
+
struct[aFeatureDef.name] = aFeatureDef
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validated_parent(aParent)
|
34
|
+
if aParent.kind_of?(FeatureStructDef)
|
35
|
+
aParent
|
36
|
+
elsif aParent
|
37
|
+
aParent.struct
|
38
|
+
else
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end # class
|
43
|
+
end # module
|
44
|
+
end # module
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require_relative 'boolean_domain'
|
2
|
+
require_relative 'identifier_domain'
|
3
|
+
require_relative 'enumeration_domain'
|
4
|
+
require_relative 'feature_def'
|
5
|
+
require_relative 'feature_value'
|
6
|
+
require_relative 'feature_struct_def'
|
7
|
+
|
8
|
+
module Zenlish
|
9
|
+
module Feature
|
10
|
+
# Mix-in module. It adds a feature structure defintion to its host and
|
11
|
+
# also factory methods to ease feature definition manipulation.
|
12
|
+
module FeatureStructDefBearer
|
13
|
+
# @param aParentStruct [Feature::FeatureStructDef] parent structure
|
14
|
+
# @param aFeatureHash [Hash] hash with pairs of the form: String => FeatureDomain
|
15
|
+
def init_struct_def(aParentStruct, aFeatureHash)
|
16
|
+
@struct = FeatureStructDef.new(aParentStruct)
|
17
|
+
aFeatureHash.each_pair do |name, domain|
|
18
|
+
feature_def(name => domain)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Feature::FeatureStructDef]
|
23
|
+
def struct
|
24
|
+
@struct
|
25
|
+
end
|
26
|
+
|
27
|
+
# Retrieve feature definition with given name.
|
28
|
+
# @param aName [String] Name of feature def to search for.
|
29
|
+
# @return [Feature::FeatureDef, NilClass]
|
30
|
+
def [](aName)
|
31
|
+
struct[aName]
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Feature::BooleanDomain]
|
35
|
+
def boolean
|
36
|
+
BooleanDomain.instance
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Feature::EnumerationDomain]
|
40
|
+
def enumeration(*items)
|
41
|
+
EnumerationDomain.new(*items)
|
42
|
+
end
|
43
|
+
|
44
|
+
def identifier(aDefaultValue = nil)
|
45
|
+
IdentifierDomain.instance
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param aPair [Hash] hash with one pair { String => FeatureDomain }
|
49
|
+
def feature_def(aPair)
|
50
|
+
if aPair.values[0].is_a?(Array)
|
51
|
+
dom, val = aPair.values[0]
|
52
|
+
val = dom.build_value(val) unless val.kind_of?(FeatureValue)
|
53
|
+
featr_def = FeatureDef.new(aPair.keys[0], dom, val)
|
54
|
+
else
|
55
|
+
featr_def = FeatureDef.new(aPair.keys[0], aPair.values[0])
|
56
|
+
end
|
57
|
+
@struct.add_feature_def(featr_def)
|
58
|
+
end
|
59
|
+
|
60
|
+
def feature_def_dsl(&aBlock)
|
61
|
+
instance_eval(&aBlock)
|
62
|
+
end
|
63
|
+
end # module
|
64
|
+
end # module
|
65
|
+
end # module
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require_relative 'feature_domain'
|
3
|
+
require_relative 'identifier_value'
|
4
|
+
|
5
|
+
module Zenlish
|
6
|
+
module Feature
|
7
|
+
class IdentifierDomain < FeatureDomain
|
8
|
+
include Singleton # Use the ingletion design pattern
|
9
|
+
|
10
|
+
def build_value(aValue)
|
11
|
+
IdentifierValue.new(validated_value(aValue))
|
12
|
+
end
|
13
|
+
|
14
|
+
def include?(aValue)
|
15
|
+
aValue =~ /^[a-zA-Z\_][a-zA-Z0-9\_]*$/
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def validated_value(aValue)
|
21
|
+
unless include?(aValue)
|
22
|
+
raise StandardError, "#{aValue} isn't a valid identifier."
|
23
|
+
end
|
24
|
+
|
25
|
+
aValue
|
26
|
+
end
|
27
|
+
end # class
|
28
|
+
end # module
|
29
|
+
end # module
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'output_expression'
|
2
|
+
|
3
|
+
module Zenlish
|
4
|
+
module Inflect
|
5
|
+
class CompositeOExpression < OutputExpression
|
6
|
+
attr_reader :children
|
7
|
+
|
8
|
+
def initialize(theChildren)
|
9
|
+
@children = theChildren.dup
|
10
|
+
end
|
11
|
+
end # class
|
12
|
+
end # module
|
13
|
+
end # module
|
14
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'literal_asis'
|
2
|
+
require_relative 'composite_o_expression'
|
3
|
+
|
4
|
+
module Zenlish
|
5
|
+
module Inflect
|
6
|
+
class Concatenation < CompositeOExpression
|
7
|
+
|
8
|
+
def initialize(argument1, argument2)
|
9
|
+
super([validated_argument(argument1), validated_argument(argument2)])
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate(headings, lexeme, values)
|
13
|
+
part1 = children[0].generate(headings, lexeme, values)
|
14
|
+
part2 = children[-1].generate(headings, lexeme, values)
|
15
|
+
|
16
|
+
part1 + part2
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def validated_argument(anArgument)
|
22
|
+
arg = nil
|
23
|
+
if anArgument.kind_of?(String)
|
24
|
+
arg = LiteralAsIs.new(anArgument)
|
25
|
+
elsif anArgument.kind_of?(OutputExpression)
|
26
|
+
arg = anArgument
|
27
|
+
else
|
28
|
+
err_msg = "Unexpected type of argument #{anArgument.inspect}."
|
29
|
+
raise StandardError, err_msg
|
30
|
+
end
|
31
|
+
|
32
|
+
arg
|
33
|
+
end
|
34
|
+
end # class
|
35
|
+
end # module
|
36
|
+
end # module
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'unary_input_expression'
|
2
|
+
|
3
|
+
module Zenlish
|
4
|
+
module Inflect
|
5
|
+
class EqualsLiteral < UnaryInputExpression
|
6
|
+
attr_reader :literal
|
7
|
+
|
8
|
+
def initialize(anArgument, aLiteral)
|
9
|
+
super(anArgument)
|
10
|
+
@literal = aLiteral
|
11
|
+
end
|
12
|
+
|
13
|
+
def success?(headings, lexeme, actuals)
|
14
|
+
if actuals.empty?
|
15
|
+
hd = headings[argument.index]
|
16
|
+
feat_def = hd.evaluate_for(lexeme)
|
17
|
+
feat_def.domain.include?(literal)
|
18
|
+
else
|
19
|
+
val = actuals[argument.index]
|
20
|
+
val == literal
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end # class
|
24
|
+
end # module
|
25
|
+
end # module
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'heading'
|
2
|
+
|
3
|
+
module Zenlish
|
4
|
+
module Inflect
|
5
|
+
class FeatureHeading < Heading
|
6
|
+
|
7
|
+
def initialize(aLabel)
|
8
|
+
super(aLabel)
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate_for(aFeatureBearer)
|
12
|
+
aFeatureBearer[label]
|
13
|
+
end
|
14
|
+
end # class
|
15
|
+
end # module
|
16
|
+
end # module
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Zenlish
|
2
|
+
module Inflect
|
3
|
+
# An inflection rule has two-parts:
|
4
|
+
# - a set of input conditions
|
5
|
+
# - a consequent part which tells how to inflect a lexeme
|
6
|
+
class InflectionRule
|
7
|
+
attr_reader :conditions
|
8
|
+
attr_reader :consequent
|
9
|
+
|
10
|
+
def initialize(theConditions, aConsequentExpr)
|
11
|
+
@conditions = theConditions
|
12
|
+
@consequent = aConsequentExpr
|
13
|
+
end
|
14
|
+
|
15
|
+
def success?(theHeadings, aLexeme, actuals)
|
16
|
+
conditions.all? { |cond| cond.success?(theHeadings, aLexeme, actuals) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def apply(theHeadings, aLexeme, actuals)
|
20
|
+
consequent.generate(theHeadings, aLexeme, actuals)
|
21
|
+
end
|
22
|
+
|
23
|
+
def force_apply(theHeadings, aLexeme)
|
24
|
+
consequent.generate(theHeadings, aLexeme)
|
25
|
+
end
|
26
|
+
end # class
|
27
|
+
end # module
|
28
|
+
end # module
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
module Zenlish
|
3
|
+
module Inflect
|
4
|
+
class InflectionTable
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :headings
|
7
|
+
attr_reader :rules
|
8
|
+
|
9
|
+
def initialize(aName)
|
10
|
+
@name = aName
|
11
|
+
@headings = []
|
12
|
+
@rules = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_heading(aHeading)
|
16
|
+
@headings << aHeading
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_rule(aRule)
|
20
|
+
@rules << aRule
|
21
|
+
end
|
22
|
+
|
23
|
+
def inflect(aLexeme, theConstraints)
|
24
|
+
err_msg = "Table has #{headings.size} headings."
|
25
|
+
raise StandardError, err_msg if theConstraints.size != headings.size
|
26
|
+
actuals = []
|
27
|
+
headings.each_with_index do |hd, idx|
|
28
|
+
if theConstraints[idx]
|
29
|
+
actuals << theConstraints[idx]
|
30
|
+
else
|
31
|
+
actuals << hd.evaluate_for(aLexeme)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
# Hit policy: first
|
35
|
+
matching_rule = rules.find do |rule|
|
36
|
+
rule.success?(headings, aLexeme, actuals)
|
37
|
+
end
|
38
|
+
unless matching_rule
|
39
|
+
err_msg = "No rule in table covers case: lexeme #{aLexeme}, actuals: #{p actuals}."
|
40
|
+
raise StandardError, err_msg
|
41
|
+
end
|
42
|
+
matching_rule.apply(headings, aLexeme, actuals)
|
43
|
+
end
|
44
|
+
end # class
|
45
|
+
end # module
|
46
|
+
end # module
|