123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- var rules = require("./rules");
- var results = require("./parsing-results");
- exports.parser = function(name, prefixRules, infixRuleBuilders) {
- var self = {
- rule: rule,
- leftAssociative: leftAssociative,
- rightAssociative: rightAssociative
- };
-
- var infixRules = new InfixRules(infixRuleBuilders.map(createInfixRule));
- var prefixRule = rules.firstOf(name, prefixRules);
-
- function createInfixRule(infixRuleBuilder) {
- return {
- name: infixRuleBuilder.name,
- rule: lazyRule(infixRuleBuilder.ruleBuilder.bind(null, self))
- };
- }
-
- function rule() {
- return createRule(infixRules);
- }
-
- function leftAssociative(name) {
- return createRule(infixRules.untilExclusive(name));
- }
-
- function rightAssociative(name) {
- return createRule(infixRules.untilInclusive(name));
- }
-
- function createRule(infixRules) {
- return apply.bind(null, infixRules);
- }
-
- function apply(infixRules, tokens) {
- var leftResult = prefixRule(tokens);
- if (leftResult.isSuccess()) {
- return infixRules.apply(leftResult);
- } else {
- return leftResult;
- }
- }
-
- return self;
- };
- function InfixRules(infixRules) {
- function untilExclusive(name) {
- return new InfixRules(infixRules.slice(0, ruleNames().indexOf(name)));
- }
-
- function untilInclusive(name) {
- return new InfixRules(infixRules.slice(0, ruleNames().indexOf(name) + 1));
- }
-
- function ruleNames() {
- return infixRules.map(function(rule) {
- return rule.name;
- });
- }
-
- function apply(leftResult) {
- var currentResult;
- var source;
- while (true) {
- currentResult = applyToTokens(leftResult.remaining());
- if (currentResult.isSuccess()) {
- source = leftResult.source().to(currentResult.source());
- leftResult = results.success(
- currentResult.value()(leftResult.value(), source),
- currentResult.remaining(),
- source
- )
- } else if (currentResult.isFailure()) {
- return leftResult;
- } else {
- return currentResult;
- }
- }
- }
-
- function applyToTokens(tokens) {
- return rules.firstOf("infix", infixRules.map(function(infix) {
- return infix.rule;
- }))(tokens);
- }
-
- return {
- apply: apply,
- untilExclusive: untilExclusive,
- untilInclusive: untilInclusive
- }
- }
- exports.infix = function(name, ruleBuilder) {
- function map(func) {
- return exports.infix(name, function(parser) {
- var rule = ruleBuilder(parser);
- return function(tokens) {
- var result = rule(tokens);
- return result.map(function(right) {
- return function(left, source) {
- return func(left, right, source);
- };
- });
- };
- });
- }
-
- return {
- name: name,
- ruleBuilder: ruleBuilder,
- map: map
- };
- }
- // TODO: move into a sensible place and remove duplication
- var lazyRule = function(ruleBuilder) {
- var rule;
- return function(input) {
- if (!rule) {
- rule = ruleBuilder();
- }
- return rule(input);
- };
- };
|