add latl parse for features
This commit is contained in:
parent
da45699c59
commit
d3ebe61577
5 changed files with 508 additions and 32 deletions
|
@ -80,9 +80,9 @@ export const addFeature = (state: stateType, action: featureAction): stateType =
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deleteFeature = (state, action) => {
|
export const deleteFeature = (state, action) => {
|
||||||
console.log('deleting')
|
const deletedFeature = state.features[action.value];
|
||||||
const deletedFeature = action.value;
|
deletedFeature.positive.forEach(phone => delete phone.features[action.value])
|
||||||
delete state.features[deletedFeature];
|
deletedFeature.negative.forEach(phone => delete phone.features[action.value])
|
||||||
console.log(state)
|
delete state.features[action.value];
|
||||||
return {...state}
|
return state
|
||||||
}
|
}
|
|
@ -31,4 +31,17 @@ describe('Features', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('feature deletion returns new feature list', () => {
|
||||||
|
const action = {type: 'DELETE_FEATURE', value: 'occlusive'}
|
||||||
|
expect(stateReducer(state, action)).toEqual(
|
||||||
|
{...state,
|
||||||
|
features: {},
|
||||||
|
phones: {
|
||||||
|
a: {features: {}, grapheme: 'a'},
|
||||||
|
n: {features: {}, grapheme: 'n'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { stateReducer } from './reducer';
|
||||||
|
|
||||||
export const setLatl = (state, action) => {
|
export const setLatl = (state, action) => {
|
||||||
let latl = action.value;
|
let latl = action.value;
|
||||||
return {...state, latl, parseResults: ''};
|
return {...state, latl, parseResults: ''};
|
||||||
|
@ -47,6 +49,14 @@ const parseLineBreak = (tree, token, index, tokens) => {
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'feature--plus': {
|
||||||
|
// tree[tree.length - 1].type === 'feature';
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
case 'feature--minus': {
|
||||||
|
// tree[tree.length - 1].type === 'feature';
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
@ -112,6 +122,32 @@ const parseReferent = (tree, token, index, tokens) => {
|
||||||
case 'ruleSet': {
|
case 'ruleSet': {
|
||||||
return [...tree, { type: 'rule', value: token.value }]
|
return [...tree, { type: 'rule', value: token.value }]
|
||||||
}
|
}
|
||||||
|
case 'feature': {
|
||||||
|
if (!lastNode.value) {
|
||||||
|
tree[tree.length - 1].value = token.value;
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'feature--plus': {
|
||||||
|
if (lastNode.value) {
|
||||||
|
lastNode.positivePhones = [...lastNode.positivePhones, token.value ]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastNode.value = token.value;
|
||||||
|
}
|
||||||
|
tree[tree.length - 1] = lastNode;
|
||||||
|
return [...tree]
|
||||||
|
}
|
||||||
|
case 'feature--minus': {
|
||||||
|
if (lastNode.value) {
|
||||||
|
lastNode.negativePhones = [...lastNode.negativePhones, token.value ]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastNode.value = token.value;
|
||||||
|
}
|
||||||
|
tree[tree.length - 1] = lastNode;
|
||||||
|
return [...tree]
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return [...tree, `unexpected referent ${token.value}`]
|
return [...tree, `unexpected referent ${token.value}`]
|
||||||
}
|
}
|
||||||
|
@ -131,17 +167,26 @@ const parsePhone = (tree, token, index, tokens) => {
|
||||||
|
|
||||||
const parseOpenBracket = (tree, token, index, tokens) => {
|
const parseOpenBracket = (tree, token, index, tokens) => {
|
||||||
const lastNode = tree[tree.length - 1];
|
const lastNode = tree[tree.length - 1];
|
||||||
switch (lastNode.type) {
|
if (lastNode) {
|
||||||
case 'epoch':
|
switch (lastNode.type) {
|
||||||
return [...tree, {type: 'rule', value: token.value}]
|
case 'epoch':
|
||||||
case 'rule':
|
return [...tree, {type: 'rule', value: token.value}]
|
||||||
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value }
|
case 'rule':
|
||||||
return tree;
|
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value }
|
||||||
case 'ruleSet':
|
return tree;
|
||||||
return [...tree, {type: 'rule', value: token.value}]
|
case 'ruleSet':
|
||||||
default:
|
return [...tree, {type: 'rule', value: token.value}];
|
||||||
return [...tree, 'unexpected open bracket']
|
// case 'feature':
|
||||||
|
// return [{type: 'feature', positivePhones: [], negativePhones: []}];
|
||||||
|
case 'feature--plus':
|
||||||
|
return [...tree, {type: 'feature', positivePhones: [], negativePhones: []}];
|
||||||
|
case 'feature--minus':
|
||||||
|
return [...tree, {type: 'feature', positivePhones: [], negativePhones: []}];
|
||||||
|
default:
|
||||||
|
return [...tree, 'unexpected open bracket']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return [{type: 'feature', positivePhones: [], negativePhones: []}]
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseCloseBracket = (tree, token, index, tokens) => {
|
const parseCloseBracket = (tree, token, index, tokens) => {
|
||||||
|
@ -150,33 +195,83 @@ const parseCloseBracket = (tree, token, index, tokens) => {
|
||||||
case 'rule':
|
case 'rule':
|
||||||
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value }
|
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value }
|
||||||
return tree;
|
return tree;
|
||||||
|
case 'feature--plus':
|
||||||
|
return tree;
|
||||||
|
case 'feature--minus':
|
||||||
|
return tree;
|
||||||
default:
|
default:
|
||||||
return [...tree, 'unexpected close bracket']
|
return [...tree, 'unexpected close bracket']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parsePositiveAssignment = (tree, token, index, tokens) => {
|
||||||
|
const lastNode = tree[tree.length - 1];
|
||||||
|
switch (lastNode.type) {
|
||||||
|
case 'feature':
|
||||||
|
tree[tree.length - 1].type = 'feature--plus'
|
||||||
|
return tree;
|
||||||
|
default:
|
||||||
|
return [...tree, 'unexpected positive assignment']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseNegativeAssignment = (tree, token, index, tokens) => {
|
||||||
|
const lastNode = tree[tree.length - 1];
|
||||||
|
switch (lastNode.type) {
|
||||||
|
case 'feature':
|
||||||
|
tree[tree.length - 1].type = 'feature--minus'
|
||||||
|
return tree;
|
||||||
|
case 'feature--plus':
|
||||||
|
tree[tree.length - 1].type = 'feature--minus';
|
||||||
|
return tree;
|
||||||
|
default:
|
||||||
|
return [...tree, 'unexpected negative assignment']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const parsePlus = (tree, token, index, tokens) => {
|
const parsePlus = (tree, token, index, tokens) => {
|
||||||
const lastNode = tree[tree.length - 1];
|
const lastNode = tree[tree.length - 1];
|
||||||
switch (lastNode.type) {
|
switch (lastNode.type) {
|
||||||
case 'rule':
|
case 'rule':
|
||||||
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value}
|
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value}
|
||||||
return tree;
|
return tree;
|
||||||
|
case 'feature':
|
||||||
|
tree[tree.length - 1] = {...lastNode, type: 'feature--plus'}
|
||||||
|
return tree;
|
||||||
|
case 'feature--minus':
|
||||||
|
tree[tree.length - 1] = {...lastNode, type: 'feature--minus'}
|
||||||
|
return tree;
|
||||||
default:
|
default:
|
||||||
return [...tree, 'unexpected plus']
|
return [...tree, 'unexpected plus']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseMinus = (tree, token, index, tokens) => {
|
const parseMinus = (tree, token, index, tokens) => {
|
||||||
const lastNode = tree[tree.length - 1];
|
const lastNode = tree[tree.length - 1];
|
||||||
switch (lastNode.type) {
|
switch (lastNode.type) {
|
||||||
case 'rule':
|
case 'rule':
|
||||||
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value}
|
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value}
|
||||||
return tree;
|
return tree;
|
||||||
|
case 'feature':
|
||||||
|
tree[tree.length - 1] = {...lastNode, type: 'feature--minus'}
|
||||||
|
return tree;
|
||||||
default:
|
default:
|
||||||
return [...tree, 'unexpected minus']
|
return [...tree, 'unexpected minus']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parseEqual = (tree, token, index, tokens) => {
|
||||||
|
const lastNode = tree[tree.length - 1];
|
||||||
|
switch (lastNode.type) {
|
||||||
|
case 'feature--plus':
|
||||||
|
return tree;
|
||||||
|
case 'feature--minus':
|
||||||
|
return tree;
|
||||||
|
default:
|
||||||
|
return [...tree, 'unexpected equal'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const parseGreaterThan = (tree, token, index, tokens) => {
|
const parseGreaterThan = (tree, token, index, tokens) => {
|
||||||
const lastNode = tree[tree.length - 1];
|
const lastNode = tree[tree.length - 1];
|
||||||
switch (lastNode.type) {
|
switch (lastNode.type) {
|
||||||
|
@ -194,6 +289,10 @@ const parseSlash = (tree, token, index, tokens) => {
|
||||||
case 'rule':
|
case 'rule':
|
||||||
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value}
|
tree[tree.length - 1] = {...lastNode, value: lastNode.value + token.value}
|
||||||
return tree;
|
return tree;
|
||||||
|
case 'feature--plus':
|
||||||
|
return tree;
|
||||||
|
case 'feature--minus':
|
||||||
|
return tree;
|
||||||
default:
|
default:
|
||||||
return [...tree, 'unexpected slash']
|
return [...tree, 'unexpected slash']
|
||||||
}
|
}
|
||||||
|
@ -254,10 +353,16 @@ const generateNode = (tree, token, index, tokens) => {
|
||||||
return parseOpenBracket(tree, token, index, tokens);
|
return parseOpenBracket(tree, token, index, tokens);
|
||||||
case 'closeBracket':
|
case 'closeBracket':
|
||||||
return parseCloseBracket(tree, token, index, tokens);
|
return parseCloseBracket(tree, token, index, tokens);
|
||||||
|
case 'positiveAssignment':
|
||||||
|
return parsePositiveAssignment(tree, token, index, tokens);
|
||||||
|
case 'negativeAssignment':
|
||||||
|
return parseNegativeAssignment(tree, token, index, tokens);
|
||||||
case 'plus':
|
case 'plus':
|
||||||
return parsePlus(tree, token, index, tokens);
|
return parsePlus(tree, token, index, tokens);
|
||||||
case 'minus':
|
case 'minus':
|
||||||
return parseMinus(tree, token, index, tokens);
|
return parseMinus(tree, token, index, tokens);
|
||||||
|
case 'equal':
|
||||||
|
return parseEqual(tree, token, index, tokens);
|
||||||
case 'greaterThan':
|
case 'greaterThan':
|
||||||
return parseGreaterThan(tree, token, index, tokens);
|
return parseGreaterThan(tree, token, index, tokens);
|
||||||
case 'slash':
|
case 'slash':
|
||||||
|
@ -279,7 +384,30 @@ const connectNodes = (tree, node, index, nodes) => {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'epoch':
|
case 'epoch':
|
||||||
delete node.type;
|
delete node.type;
|
||||||
return {...tree, epochs: [...tree.epochs, {...node, index: tree.epochs.length} ]}
|
return {...tree, epochs: [...tree.epochs, {...node, index: tree.epochs.length } ] }
|
||||||
|
case 'feature':
|
||||||
|
node.feature = node.value;
|
||||||
|
delete node.value;
|
||||||
|
delete node.type;
|
||||||
|
return {...tree, features: [...tree.features, {...node } ] }
|
||||||
|
case 'feature--minus':
|
||||||
|
node.feature = node.value;
|
||||||
|
delete node.value;
|
||||||
|
delete node.type;
|
||||||
|
if (tree.features.length && tree.features[tree.features.length - 1].feature === node.feature) {
|
||||||
|
tree.features[tree.features.length - 1].negativePhones = node.negativePhones
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
return {...tree, features: [...tree.features, {...node} ] }
|
||||||
|
case 'feature--plus':
|
||||||
|
delete node.type;
|
||||||
|
node.feature = node.value;
|
||||||
|
delete node.value;
|
||||||
|
if (tree.features.length && tree.features[tree.features.length - 1].feature === node.feature) {
|
||||||
|
tree.features[tree.features.length - 1].positivePhones = node.positivePhones
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
return {...tree, features: [...tree.features, {...node} ] }
|
||||||
default:
|
default:
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
@ -288,11 +416,18 @@ const connectNodes = (tree, node, index, nodes) => {
|
||||||
export const buildTree = tokens => {
|
export const buildTree = tokens => {
|
||||||
const bareTree = {
|
const bareTree = {
|
||||||
epochs: [],
|
epochs: [],
|
||||||
|
features: [],
|
||||||
|
phones: []
|
||||||
}
|
}
|
||||||
const nodes = tokens.reduce(addToken, []);
|
const nodes = tokens.reduce(addToken, []);
|
||||||
// return nodes
|
// return nodes
|
||||||
const tree = nodes.reduce(connectNodes, bareTree);
|
const tree = nodes.reduce(connectNodes, bareTree);
|
||||||
return tree;
|
const filterProps = Object.entries(tree).filter(([key, value]) => !value.length)
|
||||||
|
.map(([key, value]) => key)
|
||||||
|
return filterProps.reduce((tree, badProp) => {
|
||||||
|
delete tree[badProp];
|
||||||
|
return tree;
|
||||||
|
}, tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateAST = latl => {
|
export const generateAST = latl => {
|
||||||
|
@ -307,6 +442,16 @@ export const parseLatl = (state, action) => {
|
||||||
try {
|
try {
|
||||||
const latl = state.latl;
|
const latl = state.latl;
|
||||||
const AST = generateAST(latl);
|
const AST = generateAST(latl);
|
||||||
|
const features = AST.features;
|
||||||
|
if (features) {
|
||||||
|
if (state.features) {
|
||||||
|
state = Object.keys(state.features).reduce((state, feature) => {
|
||||||
|
return stateReducer(state, {type: 'DELETE_FEATURE', value: feature})
|
||||||
|
}, state)
|
||||||
|
}
|
||||||
|
state = features.reduce((state, feature) => stateReducer(state, {type:'ADD_FEATURE', value: feature}), state);
|
||||||
|
}
|
||||||
|
delete AST.features;
|
||||||
Object.entries(AST).forEach(([key, value]) => state[key] = value);
|
Object.entries(AST).forEach(([key, value]) => state[key] = value);
|
||||||
return { ...state, parseResults: 'latl parsed successfully', results:[] }
|
return { ...state, parseResults: 'latl parsed successfully', results:[] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,10 @@ describe('LATL', () => {
|
||||||
expect(tokens).toStrictEqual(tokenizedEpoch)
|
expect(tokens).toStrictEqual(tokenizedEpoch)
|
||||||
});
|
});
|
||||||
|
|
||||||
// it('returns tokens from well-formed latl feature definition', () => {
|
it('returns tokens from well-formed latl feature definition', () => {
|
||||||
// const tokens = tokenize(featureDefinitionLatl);
|
const tokens = tokenize(featureDefinitionLatl);
|
||||||
// expect(tokens).toStrictEqual(tokenizedFeature);
|
expect(tokens).toStrictEqual(tokenizedFeature);
|
||||||
// });
|
});
|
||||||
|
|
||||||
// it('returns tokens from well-formed latl lexicon definition', () => {
|
// it('returns tokens from well-formed latl lexicon definition', () => {
|
||||||
// const tokens = tokenize(lexiconDefinitionLatl);
|
// const tokens = tokenize(lexiconDefinitionLatl);
|
||||||
|
@ -41,6 +41,22 @@ describe('LATL', () => {
|
||||||
expect(tree).toStrictEqual(treeEpoch);
|
expect(tree).toStrictEqual(treeEpoch);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('returns AST from well-formed feature tokens', () => {
|
||||||
|
const tree = buildTree(tokenizedFeature);
|
||||||
|
expect(tree).toStrictEqual(treeFeature);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('parse returns state from well-formed feature latl', () => {
|
||||||
|
const state = initState();
|
||||||
|
const setAction = {
|
||||||
|
type: 'SET_LATL',
|
||||||
|
value: featureDefinitionLatl
|
||||||
|
}
|
||||||
|
const latlState = stateReducer(state, setAction);
|
||||||
|
const parseState = parseLatl(latlState, {});
|
||||||
|
expect(parseState).toStrictEqual(featureState)
|
||||||
|
})
|
||||||
|
|
||||||
it('returns run from well-formed epoch latl', () => {
|
it('returns run from well-formed epoch latl', () => {
|
||||||
const state = initState();
|
const state = initState();
|
||||||
const setAction = {
|
const setAction = {
|
||||||
|
@ -116,25 +132,327 @@ const epochState = {
|
||||||
const featureDefinitionLatl = `
|
const featureDefinitionLatl = `
|
||||||
[+ PLOSIVE] = kp/p/b/d/t/g/k
|
[+ PLOSIVE] = kp/p/b/d/t/g/k
|
||||||
[- PLOSIVE] = m/n/s/z
|
[- PLOSIVE] = m/n/s/z
|
||||||
[SONORANT
|
[SONORANT
|
||||||
+= m/n
|
+= m/n
|
||||||
-= s/z/kp/p/b/d/t/g/k
|
-= s/z/kp/p/b/d/t/g/k
|
||||||
]
|
]
|
||||||
`
|
`
|
||||||
|
|
||||||
const tokenizedFeature = [
|
const tokenizedFeature = [
|
||||||
{ type: "openBracket", value: "[" }, { type: "plus", value: "+" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "PLOSIVE" }, { type: "closeBracket", value: "]" }, { type: "whiteSpace", value: "" },
|
{type: "openBracket", value: "[" }, { type: "plus", value: "+" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "PLOSIVE" }, { type: "closeBracket", value: "]" }, { type: "whiteSpace", value: "" },
|
||||||
{ type: "equal", value: "=" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "kp" }, { type: "slash", value: "/" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "p" }, { type: "slash", value: "/" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "b" }, { type: "slash", value: "/" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "d" }, { type: "slash", value: "/" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "t" }, { type: "slash", value: "/" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "g" }, { type: "slash", value: "/" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "k" }, { type: "whiteSpace", value: "" }, { type: 'lineBreak', value: '' },
|
{ type: "equal", value: "=" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "kp" }, { type: "slash", value: "/" }, { type: "referent", value: "p" }, { type: "slash", value: "/" }, { type: "referent", value: "b" }, { type: "slash", value: "/" }, { type: "referent", value: "d" }, { type: "slash", value: "/" }, { type: "referent", value: "t" }, { type: "slash", value: "/" }, { type: "referent", value: "g" }, { type: "slash", value: "/" }, { type: "referent", value: "k" }, { type: 'lineBreak', value: '' },
|
||||||
{ type: "openBracket", value: "[" }, { type: "minus", value: "-" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "PLOSIVE" }, { type: "closeBracket", value: "]" }, { type: "whiteSpace", value: "" },
|
{type: "openBracket", value: "[" }, { type: "minus", value: "-" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "PLOSIVE" }, { type: "closeBracket", value: "]" }, { type: "whiteSpace", value: "" },
|
||||||
{ type: "equal", value: "=" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "m" }, { type: "slash", value: "/" }, { type: "referent", value: "n" }, { type: "slash", value: "/" }, { type: "referent", value: "s" }, { type: "slash", value: "/" }, { type: "referent", value: "z" }, { type: 'lineBreak', value: '' },
|
{ type: "equal", value: "=" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "m" }, { type: "slash", value: "/" }, { type: "referent", value: "n" }, { type: "slash", value: "/" }, { type: "referent", value: "s" }, { type: "slash", value: "/" }, { type: "referent", value: "z" }, { type: 'lineBreak', value: '' },
|
||||||
{ type: "openBracket", value: "[" }, { type: "referent", value: "SONORANT" }, { type: 'lineBreak', value: '' },
|
{type: "openBracket", value: "[" }, { type: "referent", value: "SONORANT" }, { type: 'lineBreak', value: '' },
|
||||||
{ type: "whiteSpace", value: "" },{ type: "whiteSpace", value: "" },{ type: "positiveAssignment", value: "+=" }, { type: "whiteSpace", value: "" },
|
{ type: "whiteSpace", value: "" }, { type: "positiveAssignment", value: "+=" }, { type: "whiteSpace", value: "" },
|
||||||
{ type: "referent", value: "m" }, { type: "slash", value: "/" }, { type: "whiteSpace", value: "" }, { type: "referent", value: "n" }, { type: 'lineBreak', value: '' },
|
{ type: "referent", value: "m" }, { type: "slash", value: "/" }, { type: "referent", value: "n" }, { type: 'lineBreak', value: '' },
|
||||||
{ type: "whiteSpace", value: "" }, { type: "whiteSpace", value: "" },{ type: "negativeAssignment", value: "-=" }, { type: "whiteSpace", value: "" },
|
{ type: "whiteSpace", value: "" }, { type: "negativeAssignment", value: "-=" }, { type: "whiteSpace", value: "" },
|
||||||
{ type: "referent", value: "s" }, { type: "slash", value: "/" }, { type: "referent", value: "z" }, { type: "slash", value: "/" }, { type: "referent", value: "kp" }, { type: "slash", value: "/" }, { type: "referent", value: "p" }, { type: "slash", value: "/" }, { type: "referent", value: "b" }, { type: "slash", value: "/" }, { type: "referent", value: "d" }, { type: "slash", value: "/" }, { type: "referent", value: "t" }, { type: "slash", value: "/" }, { type: "referent", value: "g" }, { type: "slash", value: "/" }, { type: "referent", value: "k" }, { type: "whiteSpace", value: "" },{ type: 'lineBreak', value: '' },
|
{ type: "referent", value: "s" }, { type: "slash", value: "/" }, { type: "referent", value: "z" }, { type: "slash", value: "/" }, { type: "referent", value: "kp" }, { type: "slash", value: "/" }, { type: "referent", value: "p" }, { type: "slash", value: "/" }, { type: "referent", value: "b" }, { type: "slash", value: "/" }, { type: "referent", value: "d" }, { type: "slash", value: "/" }, { type: "referent", value: "t" }, { type: "slash", value: "/" }, { type: "referent", value: "g" }, { type: "slash", value: "/" }, { type: "referent", value: "k" }, { type: 'lineBreak', value: '' },
|
||||||
{ type: "closeBracket", value: "]" },
|
{ type: "closeBracket", value: "]" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const treeFeature = { features: [
|
||||||
|
{
|
||||||
|
feature: 'PLOSIVE',
|
||||||
|
positivePhones: ['kp', 'p', 'b', 'd', 't', 'g', 'k'],
|
||||||
|
negativePhones: ['m', 'n', 's', 'z']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feature: 'SONORANT',
|
||||||
|
positivePhones: ['m', 'n'],
|
||||||
|
negativePhones: ['s' ,'z' ,'kp' ,'p' ,'b' ,'d' ,'t' ,'g' ,'k']
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
|
||||||
|
const featureState = {
|
||||||
|
...initState(),
|
||||||
|
features: {
|
||||||
|
PLOSIVE: {
|
||||||
|
negative: [
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: true,
|
||||||
|
},
|
||||||
|
grapheme: "m",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: true,
|
||||||
|
},
|
||||||
|
grapheme: "n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
positive: [
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
},
|
||||||
|
grapheme: "kp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "p",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "d",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "t",
|
||||||
|
ʰ: {
|
||||||
|
features: {},
|
||||||
|
grapheme: "tʰ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "g",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "k",
|
||||||
|
p: {
|
||||||
|
features: {
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "kp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
SONORANT: {
|
||||||
|
negative: [
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "kp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "p",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "d",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "t",
|
||||||
|
ʰ: {
|
||||||
|
features: {},
|
||||||
|
grapheme: "tʰ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "g",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "k",
|
||||||
|
p: {
|
||||||
|
features: {
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "kp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
positive: [
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: true,
|
||||||
|
},
|
||||||
|
grapheme: "m",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: true,
|
||||||
|
},
|
||||||
|
grapheme: "n",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, },
|
||||||
|
parseResults: 'latl parsed successfully',
|
||||||
|
latl: featureDefinitionLatl,
|
||||||
|
phones: {
|
||||||
|
a: {
|
||||||
|
features: {},
|
||||||
|
grapheme: "a",
|
||||||
|
},
|
||||||
|
b: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "b",
|
||||||
|
},
|
||||||
|
d: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "d",
|
||||||
|
},
|
||||||
|
g: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "g",
|
||||||
|
},
|
||||||
|
k: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "k",
|
||||||
|
p: {
|
||||||
|
features: {
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "kp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
m: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: true,
|
||||||
|
},
|
||||||
|
grapheme: "m",
|
||||||
|
},
|
||||||
|
n: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: true,
|
||||||
|
},
|
||||||
|
grapheme: "n",
|
||||||
|
},
|
||||||
|
p: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "p",
|
||||||
|
},
|
||||||
|
s: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "s",
|
||||||
|
},
|
||||||
|
t: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: true,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "t",
|
||||||
|
ʰ: {
|
||||||
|
features: {},
|
||||||
|
grapheme: "tʰ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
u: {
|
||||||
|
features: {},
|
||||||
|
grapheme: "u",
|
||||||
|
},
|
||||||
|
z: {
|
||||||
|
features: {
|
||||||
|
PLOSIVE: false,
|
||||||
|
SONORANT: false,
|
||||||
|
},
|
||||||
|
grapheme: "z",
|
||||||
|
},
|
||||||
|
ə: {
|
||||||
|
features: {},
|
||||||
|
grapheme: "ə",
|
||||||
|
},
|
||||||
|
ɯ: {
|
||||||
|
features: {},
|
||||||
|
grapheme: "ɯ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const lexiconDefinitionLatl = `
|
const lexiconDefinitionLatl = `
|
||||||
/PROTO
|
/PROTO
|
||||||
kpn
|
kpn
|
||||||
|
|
|
@ -211,7 +211,7 @@ const transformLexemeInitial = (newLexeme, pre, post, position, phoneme, index,
|
||||||
if (!isEnvironmentBoundByRule(lexemeBundle.slice(index + position.length, index + post.length + position.length), post)) return [...newLexeme, phoneme];
|
if (!isEnvironmentBoundByRule(lexemeBundle.slice(index + position.length, index + post.length + position.length), post)) return [...newLexeme, phoneme];
|
||||||
const newPhoneme = transformPhoneme(phoneme, newFeatures[0], features);
|
const newPhoneme = transformPhoneme(phoneme, newFeatures[0], features);
|
||||||
// if deletion occurs
|
// if deletion occurs
|
||||||
if (!newPhoneme.grapheme) return [ ...newLexeme] ;
|
if (!newPhoneme || !newPhoneme.grapheme) return [ ...newLexeme] ;
|
||||||
return [...newLexeme, newPhoneme];
|
return [...newLexeme, newPhoneme];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue