zenlish 0.1.25 → 0.2.00
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|