add error messages for rule syntax
This commit is contained in:
parent
66be6e0650
commit
54dbe75a70
3 changed files with 137 additions and 80 deletions
|
@ -15,8 +15,8 @@ export const initState = (changesArgument: number): stateType => {
|
|||
'a>ɯ/._#',
|
||||
'[+ sonorant - low rounded high back]>0/._.',
|
||||
'[+ obstruent]>[+ obstruent aspirated ]/#_.',
|
||||
'[+ sonorant - rounded]>[+ sonorant + rounded]/._#'
|
||||
// 'nn>nun/._.',
|
||||
'[+ sonorant - rounded]>[+ sonorant + rounded]/._#',
|
||||
'nn>nun/._.'
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -64,12 +64,28 @@ const findFeaturesFromGrapheme = (phones: {}, lexeme:string): [] => {
|
|||
return featureBundle;
|
||||
}
|
||||
|
||||
const decomposeRule = (rule: string): ruleBundle => {
|
||||
const errorMessage = ([prefix, separator], location, err) => `${prefix}${location}${separator}${err}`
|
||||
|
||||
const lintRule = (rule) => {
|
||||
if (rule.match(/>/g) === null) throw `Insert '>' operator between target and result`
|
||||
if (rule.match(/\//g) === null) throw `Insert '/' operator between change and environment`
|
||||
if (rule.match(/_/g) === null) throw `Insert '_' operator in environment`
|
||||
if (rule.match(/>/g).length > 1) throw `Too many '>' operators`
|
||||
if (rule.match(/\//g).length > 1) throw `Too many '/' operators`
|
||||
if (rule.match(/_/g).length > 1) throw `Too many '_' operators`
|
||||
return rule.split(/>|\/|_/g);
|
||||
}
|
||||
|
||||
const decomposeRule = (rule: string, index: number): ruleBundle => {
|
||||
// splits rule at '>' '/' and '_' substrings resulting in array of length 4
|
||||
const [position, newFeatures, pre, post] = rule.split(/>|\/|_/g);
|
||||
return {
|
||||
environment: { pre, position, post },
|
||||
newFeatures
|
||||
try {
|
||||
const [position, newFeatures, pre, post] = lintRule(rule);
|
||||
return {
|
||||
environment: { pre, position, post },
|
||||
newFeatures
|
||||
}
|
||||
} catch (err) {
|
||||
throw errorMessage`Error in line ${index + 1}: ${err}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +141,13 @@ const mapRuleBundleToFeatureBundle = phones => ruleBundle => {
|
|||
|
||||
export const decomposeRules = (epoch: epochType, phones: {[key: string]: phoneType}): decomposedRulesType => {
|
||||
const { changes } = epoch
|
||||
return changes.map(decomposeRule).map(mapRuleBundleToFeatureBundle(phones));
|
||||
try {
|
||||
return changes
|
||||
.map(decomposeRule)
|
||||
.map(mapRuleBundleToFeatureBundle(phones));
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const isPhonemeBoundByRule = phonemeFeatures => (ruleFeature, index) => {
|
||||
|
|
|
@ -14,77 +14,54 @@ describe('Results', () => {
|
|||
});
|
||||
|
||||
it('rules decomposed properly', () => {
|
||||
const epoch = initState().epochs[0];
|
||||
epoch.changes = epoch.changes.slice(0,1)
|
||||
const phones = initState().phones;
|
||||
const result = [
|
||||
{
|
||||
// ! '[+ occlusive - nasal]>[+ occlusive nasal]/n_',
|
||||
environment: {
|
||||
pre: [
|
||||
{
|
||||
sonorant: true, nasal: true, occlusive: true, coronal: true
|
||||
}
|
||||
],
|
||||
position: [
|
||||
{occlusive: true, nasal: false}
|
||||
],
|
||||
post: [],
|
||||
},
|
||||
newFeatures: [{occlusive: true, nasal: true}]
|
||||
}
|
||||
];
|
||||
expect(decomposeRules(epoch, phones)).toStrictEqual(result);
|
||||
const { epochs, phones } = initState(1);
|
||||
const result = getResult();
|
||||
expect(decomposeRules(epochs[0], phones)).toStrictEqual(result);
|
||||
});
|
||||
|
||||
it('expect transform lexeme to apply rule to lexeme', () => {
|
||||
const lexemeBundle = [
|
||||
{
|
||||
grapheme: 'a',
|
||||
features: {
|
||||
sonorant: true,
|
||||
back: true,
|
||||
low: true,
|
||||
high: false,
|
||||
rounded: false
|
||||
}
|
||||
},
|
||||
{
|
||||
grapheme: 'n',
|
||||
features: { sonorant: true, nasal: true, occlusive: true, coronal: true }
|
||||
},
|
||||
{
|
||||
grapheme: 't',
|
||||
features: { occlusive: true, coronal: true, obstruent: true, nasal: false }
|
||||
},
|
||||
{
|
||||
grapheme: 'a',
|
||||
features: {
|
||||
sonorant: true,
|
||||
back: true,
|
||||
low: true,
|
||||
high: false,
|
||||
rounded: false
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const resultsLexeme = [...lexemeBundle]
|
||||
resultsLexeme[2] = lexemeBundle[1]
|
||||
|
||||
const rule = {
|
||||
environment: {
|
||||
pre: [ { sonorant: true, nasal: true, occlusive: true, coronal: true } ],
|
||||
position: [ { occlusive: true, nasal: false } ],
|
||||
post: []
|
||||
},
|
||||
newFeatures: [ { occlusive: true, nasal: true } ]
|
||||
}
|
||||
|
||||
expect(transformLexeme(lexemeBundle, rule, initState().features)).toEqual(resultsLexeme)
|
||||
|
||||
it('rule without ">" returns helpful error message', () => {
|
||||
const { phones } = initState();
|
||||
const epoch = { name: 'error epoch', changes: [ 't/n/_' ] }
|
||||
expect(decomposeRules(epoch, phones)).toEqual("Error in line 1: Insert '>' operator between target and result");
|
||||
})
|
||||
|
||||
it('rule with too many ">" returns helpful error message', () => {
|
||||
const { phones } = initState();
|
||||
const epoch = { name: 'error epoch', changes: [ 't>n>/_' ] }
|
||||
expect(decomposeRules(epoch, phones)).toEqual("Error in line 1: Too many '>' operators");
|
||||
})
|
||||
|
||||
it('rule without "/" returns helpful error message', () => {
|
||||
const { phones } = initState();
|
||||
const epoch = { name: 'error epoch', changes: [ 't>n_' ] }
|
||||
expect(decomposeRules(epoch, phones)).toEqual("Error in line 1: Insert '/' operator between change and environment");
|
||||
})
|
||||
|
||||
it('rule with too many "/" returns helpful error message', () => {
|
||||
const { phones } = initState();
|
||||
const epoch = { name: 'error epoch', changes: [ 't>n/_/' ] }
|
||||
expect(decomposeRules(epoch, phones)).toEqual("Error in line 1: Too many '/' operators");
|
||||
})
|
||||
|
||||
it('rule without "_" returns helpful error message', () => {
|
||||
const { phones } = initState();
|
||||
const epoch = { name: 'error epoch', changes: [ 't>n/' ] }
|
||||
expect(decomposeRules(epoch, phones)).toEqual("Error in line 1: Insert '_' operator in environment");
|
||||
})
|
||||
|
||||
it('rule with too many "_" returns helpful error message', () => {
|
||||
const { phones } = initState();
|
||||
const epoch = { name: 'error epoch', changes: [ 't>n/__' ] }
|
||||
expect(decomposeRules(epoch, phones)).toEqual("Error in line 1: Too many '_' operators");
|
||||
})
|
||||
|
||||
it('expect transform lexeme to apply rule to lexeme', () => {
|
||||
const lexemeBundle = getlexemeBundle();
|
||||
const resultsLexeme = [...lexemeBundle]
|
||||
resultsLexeme[2] = lexemeBundle[1]
|
||||
const rule = getRule();
|
||||
expect(transformLexeme(lexemeBundle, rule, initState().features)).toEqual(resultsLexeme)
|
||||
})
|
||||
|
||||
it('results returned from first sound change rule', () => {
|
||||
const action = {type: 'RUN'};
|
||||
|
@ -151,18 +128,76 @@ describe('Results', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// if('results returned from sound change suite', () => {
|
||||
|
||||
// it('results returned through sixth sound change rule', () => {
|
||||
// const action = {type: 'RUN'};
|
||||
// state = initState()
|
||||
// console.log(stateReducer(state, action).results)
|
||||
// state = initState(5)
|
||||
// expect(stateReducer(state, action).results).toEqual([
|
||||
// {
|
||||
// pass: 'epoch 1',
|
||||
// lexicon: [
|
||||
// 'anna', 'anta', 'anət', 'anna', 'tan', 'ənna'
|
||||
// 'anunu', 'anat', 'ant', 'anunu', 'tʰan', 'nunu'
|
||||
// ]
|
||||
// }
|
||||
// ]);
|
||||
// });
|
||||
|
||||
});
|
||||
|
||||
|
||||
const getlexemeBundle = () => ([
|
||||
{
|
||||
grapheme: 'a',
|
||||
features: {
|
||||
sonorant: true,
|
||||
back: true,
|
||||
low: true,
|
||||
high: false,
|
||||
rounded: false
|
||||
}
|
||||
},
|
||||
{
|
||||
grapheme: 'n',
|
||||
features: { sonorant: true, nasal: true, occlusive: true, coronal: true }
|
||||
},
|
||||
{
|
||||
grapheme: 't',
|
||||
features: { occlusive: true, coronal: true, obstruent: true, nasal: false }
|
||||
},
|
||||
{
|
||||
grapheme: 'a',
|
||||
features: {
|
||||
sonorant: true,
|
||||
back: true,
|
||||
low: true,
|
||||
high: false,
|
||||
rounded: false
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
const getRule = () => ({
|
||||
environment: {
|
||||
pre: [ { sonorant: true, nasal: true, occlusive: true, coronal: true } ],
|
||||
position: [ { occlusive: true, nasal: false } ],
|
||||
post: []
|
||||
},
|
||||
newFeatures: [ { occlusive: true, nasal: true } ]
|
||||
})
|
||||
|
||||
const getResult = () => ([
|
||||
{
|
||||
environment: {
|
||||
pre: [
|
||||
{
|
||||
sonorant: true, nasal: true, occlusive: true, coronal: true
|
||||
}
|
||||
],
|
||||
position: [
|
||||
{occlusive: true, nasal: false}
|
||||
],
|
||||
post: [],
|
||||
},
|
||||
newFeatures: [{occlusive: true, nasal: true}]
|
||||
}
|
||||
]);
|
Loading…
Reference in a new issue