All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sweetjs-0.2.5.node_modules.sweet.js.lib.patterns.js Maven / Gradle / Ivy

The newest version!
(function (root$97, factory$98) {
    if (typeof exports === 'object') {
        // CommonJS
        factory$98(exports, require('underscore'), require('es6-collections'), require('./parser'), require('./expander'), require('./syntax'));
    } else if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([
            'exports',
            'underscore',
            'es6-collections',
            'parser',
            'expander',
            'syntax'
        ], factory$98);
    }
}(this, function (exports$99, _$100, es6$101, parser$102, expander$103, syntax$104) {
    var get_expression$105 = expander$103.get_expression;
    var syntaxFromToken$106 = syntax$104.syntaxFromToken;
    var makePunc$107 = syntax$104.makePunc;
    var joinSyntax$108 = syntax$104.joinSyntax;
    var joinSyntaxArr$109 = syntax$104.joinSyntaxArr;
    // ([...CSyntax]) -> [...Str]
    function freeVarsInPattern$110(pattern$123) {
        var fv$124 = [];
        _$100.each(pattern$123, function (pat$125) {
            if (isPatternVar$114(pat$125)) {
                fv$124.push(pat$125.token.value);
            } else if (pat$125.token.type === parser$102.Token.Delimiter) {
                fv$124 = fv$124.concat(freeVarsInPattern$110(pat$125.token.inner));
            }
        });
        return fv$124;
    }
    function typeIsLiteral$111(type$126) {
        return type$126 === parser$102.Token.NullLiteral || type$126 === parser$102.Token.NumericLiteral || type$126 === parser$102.Token.StringLiteral || type$126 === parser$102.Token.RegexLiteral || type$126 === parser$102.Token.BooleanLiteral;
    }
    function containsPatternVar$112(patterns$127) {
        return _$100.any(patterns$127, function (pat$128) {
            if (pat$128.token.type === parser$102.Token.Delimiter) {
                return containsPatternVar$112(pat$128.token.inner);
            }
            return isPatternVar$114(pat$128);
        });
    }
    function delimIsSeparator$113(delim$129) {
        return delim$129 && delim$129.token && delim$129.token.type === parser$102.Token.Delimiter && delim$129.token.value === '()' && delim$129.token.inner.length === 1 && delim$129.token.inner[0].token.type !== parser$102.Token.Delimiter && !containsPatternVar$112(delim$129.token.inner);
    }
    function isPatternVar$114(stx$130) {
        return stx$130.token.value[0] === '$' && stx$130.token.value !== '$';
    }
    // ([...{level: Num, match: [...CSyntax]}], Str) -> [...CSyntax]
    function joinRepeatedMatch$115(tojoin$131, punc$132) {
        return _$100.reduce(_$100.rest(tojoin$131, 1), function (acc$133, join$134) {
            if (punc$132 === ' ') {
                return acc$133.concat(join$134.match);
            }
            return acc$133.concat(makePunc$107(punc$132, _$100.first(join$134.match)), join$134.match);
        }, _$100.first(tojoin$131).match);
    }
    // take the line context (range, lineNumber)
    // (CSyntax, [...CSyntax]) -> [...CSyntax]
    function takeLineContext$116(from$135, to$136) {
        return _$100.map(to$136, function (stx$137) {
            return takeLine$117(from$135, stx$137);
        });
    }
    // (CSyntax, CSyntax) -> CSyntax
    function takeLine$117(from$138, to$139) {
        if (to$139.token.type === parser$102.Token.Delimiter) {
            if (from$138.token.type === parser$102.Token.Delimiter) {
                var next$140 = syntaxFromToken$106({
                        type: parser$102.Token.Delimiter,
                        value: to$139.token.value,
                        inner: to$139.token.inner,
                        startRange: from$138.token.startRange,
                        endRange: from$138.token.endRange,
                        startLineNumber: from$138.token.startLineNumber,
                        startLineStart: from$138.token.startLineStart,
                        endLineNumber: from$138.token.endLineNumber,
                        endLineStart: from$138.token.endLineStart
                    }, to$139);
            } else {
                var next$140 = syntaxFromToken$106({
                        type: parser$102.Token.Delimiter,
                        value: to$139.token.value,
                        inner: to$139.token.inner,
                        startRange: from$138.token.range,
                        endRange: from$138.token.range,
                        startLineNumber: from$138.token.lineNumber,
                        startLineStart: from$138.token.lineStart,
                        endLineNumber: from$138.token.lineNumber,
                        endLineStart: from$138.token.lineStart
                    }, to$139);
            }
            return next$140;
        }
        if (from$138.token.type === parser$102.Token.Delimiter) {
            return syntaxFromToken$106({
                value: to$139.token.value,
                type: to$139.token.type,
                lineNumber: from$138.token.startLineNumber,
                lineStart: from$138.token.startLineStart,
                range: from$138.token.startRange
            }, to$139);
        } else {
            return syntaxFromToken$106({
                value: to$139.token.value,
                type: to$139.token.type,
                lineNumber: from$138.token.lineNumber,
                lineStart: from$138.token.lineStart,
                range: from$138.token.range
            }, to$139);
        }
    }
    function loadPattern$118(patterns$141) {
        return _$100.chain(patterns$141).reduce(function (acc$142, patStx$143, idx$144) {
            var last$145 = patterns$141[idx$144 - 1];
            var lastLast$146 = patterns$141[idx$144 - 2];
            var next$147 = patterns$141[idx$144 + 1];
            var nextNext$148 = patterns$141[idx$144 + 2];
            // skip over the `:lit` part of `$x:lit`
            if (patStx$143.token.value === ':') {
                if (last$145 && isPatternVar$114(last$145) && !isPatternVar$114(next$147)) {
                    return acc$142;
                }
            }
            if (last$145 && last$145.token.value === ':') {
                if (lastLast$146 && isPatternVar$114(lastLast$146) && !isPatternVar$114(patStx$143)) {
                    return acc$142;
                }
            }
            // skip over $
            if (patStx$143.token.value === '$' && next$147 && next$147.token.type === parser$102.Token.Delimiter) {
                return acc$142;
            }
            if (isPatternVar$114(patStx$143)) {
                if (next$147 && next$147.token.value === ':' && !isPatternVar$114(nextNext$148)) {
                    if (typeof nextNext$148 === 'undefined') {
                        throw new Error('expecting a pattern class following a `:`');
                    }
                    patStx$143.class = nextNext$148.token.value;
                } else {
                    patStx$143.class = 'token';
                }
            } else if (patStx$143.token.type === parser$102.Token.Delimiter) {
                if (last$145 && last$145.token.value === '$') {
                    patStx$143.class = 'pattern_group';
                }
                patStx$143.token.inner = loadPattern$118(patStx$143.token.inner);
            } else {
                patStx$143.class = 'pattern_literal';
            }
            return acc$142.concat(patStx$143);
        }, []).reduce(function (acc$149, patStx$150, idx$151, patterns$152) {
            var separator$153 = ' ';
            var repeat$154 = false;
            var next$155 = patterns$152[idx$151 + 1];
            var nextNext$156 = patterns$152[idx$151 + 2];
            if (next$155 && next$155.token.value === '...') {
                repeat$154 = true;
                separator$153 = ' ';
            } else if (delimIsSeparator$113(next$155) && nextNext$156 && nextNext$156.token.value === '...') {
                repeat$154 = true;
                parser$102.assert(next$155.token.inner.length === 1, 'currently assuming all separators are a single token');
                separator$153 = next$155.token.inner[0].token.value;
            }
            // skip over ... and (,)
            if (patStx$150.token.value === '...' || delimIsSeparator$113(patStx$150) && next$155 && next$155.token.value === '...') {
                return acc$149;
            }
            patStx$150.repeat = repeat$154;
            patStx$150.separator = separator$153;
            return acc$149.concat(patStx$150);
        }, []).value();
    }
    // (Str, [...CSyntax], MacroEnv) -> {result: null or [...CSyntax], rest: [...CSyntax]}
    function matchPatternClass$119(patternClass$157, stx$158, env$159) {
        var result$160, rest$161;
        // pattern has no parse class
        if (patternClass$157 === 'token' && stx$158[0] && stx$158[0].token.type !== parser$102.Token.EOF) {
            result$160 = [stx$158[0]];
            rest$161 = stx$158.slice(1);
        } else if (patternClass$157 === 'lit' && stx$158[0] && typeIsLiteral$111(stx$158[0].token.type)) {
            result$160 = [stx$158[0]];
            rest$161 = stx$158.slice(1);
        } else if (patternClass$157 === 'ident' && stx$158[0] && stx$158[0].token.type === parser$102.Token.Identifier) {
            result$160 = [stx$158[0]];
            rest$161 = stx$158.slice(1);
        } else if (stx$158.length > 0 && patternClass$157 === 'VariableStatement') {
            var match$162 = expander$103.enforest(stx$158, env$159);
            if (match$162.result && match$162.result.hasPrototype(expander$103.VariableStatement)) {
                result$160 = match$162.result.destruct(false);
                rest$161 = match$162.rest;
            } else {
                result$160 = null;
                rest$161 = stx$158;
            }
        } else if (stx$158.length > 0 && patternClass$157 === 'expr') {
            var match$162 = expander$103.get_expression(stx$158, env$159);
            if (match$162.result === null || !match$162.result.hasPrototype(expander$103.Expr)) {
                result$160 = null;
                rest$161 = stx$158;
            } else {
                result$160 = match$162.result.destruct(false);
                rest$161 = match$162.rest;
            }
        } else {
            result$160 = null;
            rest$161 = stx$158;
        }
        return {
            result: result$160,
            rest: rest$161
        };
    }
    // attempt to match patterns against stx
    // ([...Pattern], [...Syntax], Env) -> { result: [...Syntax], rest: [...Syntax], patternEnv: PatternEnv }
    function matchPatterns$120(patterns$163, stx$164, env$165, topLevel$166) {
        // topLevel lets us know if the patterns are on the top level or nested inside
        // a delimiter:
        //     case $topLevel (,) ... => { }
        //     case ($nested (,) ...) => { }
        // This matters for how we deal with trailing unmatched syntax when the pattern
        // has an ellipses:
        //     m 1,2,3 foo
        // should match 1,2,3 and leave foo alone but:
        //     m (1,2,3 foo)
        // should fail to match entirely.
        topLevel$166 = topLevel$166 || false;
        // note that there are two environments floating around,
        // one is the mapping of identifiers to macro definitions (env)
        // and the other is the pattern environment (patternEnv) that maps
        // patterns in a macro case to syntax.
        var result$167 = [];
        var patternEnv$168 = {};
        var match$169;
        var pattern$170;
        var rest$171 = stx$164;
        var success$172 = true;
        for (var i$173 = 0; i$173 < patterns$163.length; i$173++) {
            pattern$170 = patterns$163[i$173];
            do {
                match$169 = matchPattern$121(pattern$170, rest$171, env$165, patternEnv$168);
                if (!match$169.success && pattern$170.repeat) {
                    // a repeat can match zero tokens and still be a
                    // "success" so break out of the inner loop and
                    // try the next pattern
                    rest$171 = match$169.rest;
                    patternEnv$168 = match$169.patternEnv;
                    break;
                }
                if (!match$169.success) {
                    success$172 = false;
                    break;
                }
                rest$171 = match$169.rest;
                patternEnv$168 = match$169.patternEnv;
                if (pattern$170.repeat && success$172) {
                    if (rest$171[0] && rest$171[0].token.value === pattern$170.separator) {
                        // more tokens and the next token matches the separator
                        rest$171 = rest$171.slice(1);
                    } else if (pattern$170.separator === ' ') {
                        // no separator specified (using the empty string for this)
                        // so keep going
                        continue;
                    } else if (pattern$170.separator !== ' ' && rest$171.length > 0 && i$173 === patterns$163.length - 1 && topLevel$166 === false) {
                        // separator is specified, there is a next token, the
                        // next token doesn't match the separator, there are
                        // no more patterns, and this is a top level pattern
                        // so the match has failed
                        success$172 = false;
                        break;
                    } else {
                        break;
                    }
                }
            } while (pattern$170.repeat && match$169.success && rest$171.length > 0);
        }
        return {
            success: success$172,
            rest: rest$171,
            patternEnv: patternEnv$168
        };
    }
    /* the pattern environment will look something like:
    {
        "$x": {
            level: 2,
            match: [{
                level: 1,
                match: [{
                    level: 0,
                    match: [tok1, tok2, ...]
                }, {
                    level: 0,
                    match: [tok1, tok2, ...]
                }]
            }, {
                level: 1,
                match: [{
                    level: 0,
                    match: [tok1, tok2, ...]
                }]
            }]
        },
        "$y" : ...
    }
    */
    function matchPattern$121(pattern$174, stx$175, env$176, patternEnv$177) {
        var subMatch$178;
        var match$179, matchEnv$180;
        var rest$181;
        var success$182;
        if (typeof pattern$174.inner !== 'undefined') {
            if (pattern$174.class === 'pattern_group') {
                // pattern groups don't match the delimiters
                subMatch$178 = matchPatterns$120(pattern$174.inner, stx$175, env$176, false);
                rest$181 = subMatch$178.rest;
            } else if (stx$175[0] && stx$175[0].token.type === parser$102.Token.Delimiter && stx$175[0].token.value === pattern$174.value) {
                stx$175[0].expose();
                if (pattern$174.inner.length === 0 && stx$175[0].token.inner.length !== 0) {
                    return {
                        success: false,
                        rest: stx$175,
                        patternEnv: patternEnv$177
                    };
                }
                subMatch$178 = matchPatterns$120(pattern$174.inner, stx$175[0].token.inner, env$176, false);
                rest$181 = stx$175.slice(1);
            } else {
                return {
                    success: false,
                    rest: stx$175,
                    patternEnv: patternEnv$177
                };
            }
            success$182 = subMatch$178.success;
            // merge the subpattern matches with the current pattern environment
            _$100.keys(subMatch$178.patternEnv).forEach(function (patternKey$183) {
                if (pattern$174.repeat) {
                    // if this is a repeat pattern we need to bump the level
                    var nextLevel$184 = subMatch$178.patternEnv[patternKey$183].level + 1;
                    if (patternEnv$177[patternKey$183]) {
                        patternEnv$177[patternKey$183].level = nextLevel$184;
                        patternEnv$177[patternKey$183].match.push(subMatch$178.patternEnv[patternKey$183]);
                    } else {
                        // initialize if we haven't done so already
                        patternEnv$177[patternKey$183] = {
                            level: nextLevel$184,
                            match: [subMatch$178.patternEnv[patternKey$183]]
                        };
                    }
                } else {
                    // otherwise accept the environment as-is
                    patternEnv$177[patternKey$183] = subMatch$178.patternEnv[patternKey$183];
                }
            });
        } else {
            if (pattern$174.class === 'pattern_literal') {
                // wildcard
                if (stx$175[0] && pattern$174.value === '_') {
                    success$182 = true;
                    rest$181 = stx$175.slice(1);
                } else if (stx$175[0] && pattern$174.value === stx$175[0].token.value) {
                    success$182 = true;
                    rest$181 = stx$175.slice(1);
                } else {
                    success$182 = false;
                    rest$181 = stx$175;
                }
            } else {
                match$179 = matchPatternClass$119(pattern$174.class, stx$175, env$176);
                success$182 = match$179.result !== null;
                rest$181 = match$179.rest;
                matchEnv$180 = {
                    level: 0,
                    match: match$179.result
                };
                // push the match onto this value's slot in the environment
                if (pattern$174.repeat) {
                    if (patternEnv$177[pattern$174.value]) {
                        patternEnv$177[pattern$174.value].match.push(matchEnv$180);
                    } else {
                        // initialize if necessary
                        patternEnv$177[pattern$174.value] = {
                            level: 1,
                            match: [matchEnv$180]
                        };
                    }
                } else {
                    patternEnv$177[pattern$174.value] = matchEnv$180;
                }
            }
        }
        return {
            success: success$182,
            rest: rest$181,
            patternEnv: patternEnv$177
        };
    }
    // given the given the macroBody (list of Pattern syntax objects) and the
    // environment (a mapping of patterns to syntax) return the body with the
    // appropriate patterns replaces with their value in the environment
    function transcribe$122(macroBody$185, macroNameStx$186, env$187) {
        return _$100.chain(macroBody$185).reduce(function (acc$188, bodyStx$189, idx$190, original$191) {
            // first find the ellipses and mark the syntax objects
            // (note that this step does not eagerly go into delimiter bodies)
            var last$192 = original$191[idx$190 - 1];
            var next$193 = original$191[idx$190 + 1];
            var nextNext$194 = original$191[idx$190 + 2];
            // drop `...`
            if (bodyStx$189.token.value === '...') {
                return acc$188;
            }
            // drop `( 0;
                        });
                    parser$102.assert(typeof nonScalar$200 !== 'undefined', 'must have a least one non-scalar in repeat');
                    var repeatLength$201 = env$187[nonScalar$200].match.length;
                    var sameLength$202 = _$100.all(fv$198, function (pat$207) {
                            return env$187[pat$207].level === 0 || env$187[pat$207].match.length === repeatLength$201;
                        });
                    parser$102.assert(sameLength$202, 'all non-scalars must have the same length');
                    // create a list of envs restricted to the free vars
                    restrictedEnv$199 = _$100.map(_$100.range(repeatLength$201), function (idx$208) {
                        var renv$209 = {};
                        _$100.each(fv$198, function (pat$210) {
                            if (env$187[pat$210].level === 0) {
                                // copy scalars over
                                renv$209[pat$210] = env$187[pat$210];
                            } else {
                                // grab the match at this index
                                renv$209[pat$210] = env$187[pat$210].match[idx$208];
                            }
                        });
                        return renv$209;
                    });
                    var transcribed$203 = _$100.map(restrictedEnv$199, function (renv$211) {
                            if (bodyStx$196.group) {
                                return transcribe$122(bodyStx$196.token.inner, macroNameStx$186, renv$211);
                            } else {
                                var newBody$212 = syntaxFromToken$106(_$100.clone(bodyStx$196.token), bodyStx$196);
                                newBody$212.token.inner = transcribe$122(bodyStx$196.token.inner, macroNameStx$186, renv$211);
                                return newBody$212;
                            }
                        });
                    var joined$204;
                    if (bodyStx$196.group) {
                        joined$204 = joinSyntaxArr$109(transcribed$203, bodyStx$196.separator);
                    } else {
                        joined$204 = joinSyntax$108(transcribed$203, bodyStx$196.separator);
                    }
                    return acc$195.concat(joined$204);
                }
                if (!env$187[bodyStx$196.token.value]) {
                    throw new Error('The pattern variable ' + bodyStx$196.token.value + ' is not bound for the template');
                } else if (env$187[bodyStx$196.token.value].level !== 1) {
                    throw new Error('Ellipses level for ' + bodyStx$196.token.value + ' does not match in the template');
                }
                return acc$195.concat(joinRepeatedMatch$115(env$187[bodyStx$196.token.value].match, bodyStx$196.separator));
            } else {
                if (bodyStx$196.token.type === parser$102.Token.Delimiter) {
                    bodyStx$196.expose();
                    var newBody$213 = syntaxFromToken$106(_$100.clone(bodyStx$196.token), macroBody$185);
                    newBody$213.token.inner = transcribe$122(bodyStx$196.token.inner, macroNameStx$186, env$187);
                    return acc$195.concat(takeLineContext$116(macroNameStx$186, [newBody$213]));
                }
                if (isPatternVar$114(bodyStx$196) && Object.prototype.hasOwnProperty.bind(env$187)(bodyStx$196.token.value)) {
                    if (!env$187[bodyStx$196.token.value]) {
                        throw new Error('The pattern variable ' + bodyStx$196.token.value + ' is not bound for the template');
                    } else if (env$187[bodyStx$196.token.value].level !== 0) {
                        throw new Error('Ellipses level for ' + bodyStx$196.token.value + ' does not match in the template');
                    }
                    return acc$195.concat(takeLineContext$116(macroNameStx$186, env$187[bodyStx$196.token.value].match));
                }
                return acc$195.concat(takeLineContext$116(macroNameStx$186, [bodyStx$196]));
            }
        }, []).value();
    }
    exports$99.loadPattern = loadPattern$118;
    exports$99.matchPatterns = matchPatterns$120;
    exports$99.transcribe = transcribe$122;
    exports$99.matchPatternClass = matchPatternClass$119;
    exports$99.takeLineContext = takeLineContext$116;
    exports$99.takeLine = takeLine$117;
}));




© 2015 - 2025 Weber Informatics LLC | Privacy Policy